Commit a9b84fe2 by Robbie Hott

Added Java ingest tool code

parent 37b9a04a
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" output="target/classes" path="src">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" path="schematron"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry exported="true" kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="output" path="target/classes"/>
</classpath>
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>SNAC-Java-Parser</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.m2e.core.maven2Builder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.m2e.core.maven2Nature</nature>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
org.eclipse.jdt.core.compiler.compliance=1.8
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
org.eclipse.jdt.core.compiler.source=1.8
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>SNAC-EAC-Parser</groupId>
<artifactId>SNAC-EAC-Parser</artifactId>
<version>0.0.1-SNAPSHOT</version>
<build>
<sourceDirectory>src</sourceDirectory>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.5.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-io</artifactId>
<version>1.3.2</version>
</dependency>
<dependency>
<groupId>org.json</groupId>
<artifactId>org.json</artifactId>
<version>chargebee-1.0</version>
</dependency>
<dependency>
<groupId>com.helger</groupId>
<artifactId>ph-schematron-validator</artifactId>
<version>5.0.2</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-jdk14</artifactId>
<version>1.8.0-beta2</version>
</dependency>
</dependencies>
</project>
/**
* SNAC Reconciliation Example (CBW Java Example)
*
* For the full license, see the LICENSE file in the repository root
*
* @author Robbie Hott
* @license http://opensource.org/licenses/BSD-3-Clause BSD 3-Clause
* @copyright 2017 the Rector and Visitors of the University of Virginia, and
* the Regents of the University of California
*/
import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.JScrollPane;
import javax.swing.JSeparator;
import javax.swing.JTextArea;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.filechooser.FileNameExtensionFilter;
/**
* CBW Reconciler UI
*
* This is the GUI interface class that prompts the user to choose CSV files to reconcile against SNAC.
*
* @author Robbie Hott
*
*/
public class SNACInfoWindow extends javax.swing.JFrame {
/**
* Serial ID
*/
private static final long serialVersionUID = -8115653654144568030L;
/**
* GUI Variables
*/
private JPanel titlePanel;
private JLabel titleLabel;
private JPanel bodyPanel;
private JPanel parserPanel;
private JTextArea parsedDisplay;
private String title;
private String text;
{
//Set Look & Feel
try {
javax.swing.UIManager.setLookAndFeel(javax.swing.UIManager.getSystemLookAndFeelClassName());
} catch(Exception e) {
// Silently ignoring errors
}
}
/**
* Constructor
*
* Calls JFrame's constructor and then initializes and displays the GUI
*/
public SNACInfoWindow(String title, String text) {
super();
this.title = title;
this.text = text;
initGUI();
}
public static void showWindow(String title, String text) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
SNACInfoWindow inst = new SNACInfoWindow(title, text);
inst.setLocationRelativeTo(null);
inst.setVisible(true);
}
});
}
/**
* Initialize GUI
*
* Builds the JFrame to display to the user.
*/
public void initGUI() {
try {
BorderLayout thisLayout = new BorderLayout();
getContentPane().setLayout(thisLayout);
{
titlePanel = new JPanel();
getContentPane().add(titlePanel, BorderLayout.NORTH);
titlePanel.setSize(900, 40);
{
titleLabel = new JLabel("<html><body style='text-align: center; font-size: 20px; margin: 0px; padding: 0px;'>" + title + "</body></html>", SwingConstants.CENTER);
titlePanel.add(titleLabel);
titleLabel.setPreferredSize(new java.awt.Dimension(900, 40));
}
}
//continue building GUI
bodyPanel = new JPanel();
FlowLayout bodyPanelLayout = new FlowLayout();
getContentPane().add(bodyPanel, BorderLayout.CENTER);
bodyPanel.setLayout(bodyPanelLayout);
{
parserPanel = new JPanel();
bodyPanel.add(parserPanel);
parserPanel.setSize(900, 700);
parserPanel.setPreferredSize(new java.awt.Dimension(900, 700));
parsedDisplay = new JTextArea();
parsedDisplay.setText(text.toString());
JScrollPane sp = new JScrollPane(parsedDisplay);
sp.setPreferredSize(new java.awt.Dimension(900, 700));
parserPanel.add(sp);
}
this.setSize(900, 800);
} catch (Exception e) {
// Silently ignoring errors
}
}
}
/**
* SNAC Reconciliation Example (CBW Java Example)
*
* For the full license, see the LICENSE file in the repository root
*
* @author Robbie Hott
* @license http://opensource.org/licenses/BSD-3-Clause BSD 3-Clause
* @copyright 2017 the Rector and Visitors of the University of Virginia, and
* the Regents of the University of California
*/
import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.JScrollPane;
import javax.swing.JSeparator;
import javax.swing.JTextArea;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.filechooser.FileNameExtensionFilter;
/**
* CBW Reconciler UI
*
* This is the GUI interface class that prompts the user to choose CSV files to reconcile against SNAC.
*
* @author Robbie Hott
*
*/
public class SNACJavaParserConstellationWindow extends javax.swing.JFrame {
/**
* Serial ID
*/
private static final long serialVersionUID = -8115653654144568030L;
/**
* GUI Variables
*/
private JPanel title;
private JLabel titleLabel;
private JPanel bodyPanel;
private JPanel parserPanel;
private JTextArea parsedDisplay;
{
//Set Look & Feel
try {
javax.swing.UIManager.setLookAndFeel(javax.swing.UIManager.getSystemLookAndFeelClassName());
} catch(Exception e) {
// Silently ignoring errors
}
}
/**
* Constructor
*
* Calls JFrame's constructor and then initializes and displays the GUI
*/
public SNACJavaParserConstellationWindow(String constellation) {
super();
initGUI(constellation);
}
public static void showConstellation(String constellation) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
SNACJavaParserConstellationWindow inst = new SNACJavaParserConstellationWindow(constellation);
inst.setLocationRelativeTo(null);
inst.setVisible(true);
}
});
}
/**
* Initialize GUI
*
* Builds the JFrame to display to the user.
*/
public void initGUI(String constellation) {
try {
BorderLayout thisLayout = new BorderLayout();
getContentPane().setLayout(thisLayout);
{
title = new JPanel();
getContentPane().add(title, BorderLayout.NORTH);
title.setSize(900, 40);
{
titleLabel = new JLabel("<html><body style='text-align: center; font-size: 20px; margin: 0px; padding: 0px;'>Parsed Constellation</body></html>", SwingConstants.CENTER);
title.add(titleLabel);
titleLabel.setPreferredSize(new java.awt.Dimension(900, 40));
}
}
//continue building GUI
bodyPanel = new JPanel();
FlowLayout bodyPanelLayout = new FlowLayout();
getContentPane().add(bodyPanel, BorderLayout.CENTER);
bodyPanel.setLayout(bodyPanelLayout);
{
parserPanel = new JPanel();
bodyPanel.add(parserPanel);
parserPanel.setSize(900, 700);
parserPanel.setPreferredSize(new java.awt.Dimension(900, 700));
parsedDisplay = new JTextArea();
parsedDisplay.setText(constellation.toString());
JScrollPane sp = new JScrollPane(parsedDisplay);
sp.setPreferredSize(new java.awt.Dimension(900, 700));
parserPanel.add(sp);
}
this.setSize(900, 800);
} catch (Exception e) {
// Silently ignoring errors
}
}
}
/**
* SNAC Reconciliation Example (CBW Java Example)
*
* For the full license, see the LICENSE file in the repository root
*
* @author Robbie Hott
* @license http://opensource.org/licenses/BSD-3-Clause BSD 3-Clause
* @copyright 2017 the Rector and Visitors of the University of Virginia, and
* the Regents of the University of California
*/
import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.JScrollPane;
import javax.swing.JSeparator;
import javax.swing.JTextArea;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.filechooser.FileNameExtensionFilter;
/**
* CBW Reconciler UI
*
* This is the GUI interface class that prompts the user to choose CSV files to reconcile against SNAC.
*
* @author Robbie Hott
*
*/
public class SNACJavaParserErrorWindow extends javax.swing.JFrame {
/**
* Serial ID
*/
private static final long serialVersionUID = -8115653654144568030L;
/**
* GUI Variables
*/
private JPanel title;
private JLabel titleLabel;
private JPanel bodyPanel;
private JPanel parserPanel;
private JTextArea parseErrors;
{
//Set Look & Feel
try {
javax.swing.UIManager.setLookAndFeel(javax.swing.UIManager.getSystemLookAndFeelClassName());
} catch(Exception e) {
// Silently ignoring errors
}
}
/**
* Constructor
*
* Calls JFrame's constructor and then initializes and displays the GUI
*/
public SNACJavaParserErrorWindow(String errors) {
super();
initGUI(errors);
}
public static void showErrors(String errors) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
SNACJavaParserErrorWindow inst = new SNACJavaParserErrorWindow(errors);
inst.setLocationRelativeTo(null);
inst.setVisible(true);
}
});
}
/**
* Initialize GUI
*
* Builds the JFrame to display to the user.
*/
public void initGUI(String errors) {
try {
BorderLayout thisLayout = new BorderLayout();
getContentPane().setLayout(thisLayout);
{
title = new JPanel();
getContentPane().add(title, BorderLayout.NORTH);
title.setSize(900, 40);
{
titleLabel = new JLabel("<html><body style='text-align: center; font-size: 20px;'>Parse Errors</body></html>", SwingConstants.CENTER);
title.add(titleLabel);
titleLabel.setPreferredSize(new java.awt.Dimension(900, 40));
}
}
//continue building GUI
bodyPanel = new JPanel();
FlowLayout bodyPanelLayout = new FlowLayout();
getContentPane().add(bodyPanel, BorderLayout.CENTER);
bodyPanel.setLayout(bodyPanelLayout);
{
parserPanel = new JPanel();
bodyPanel.add(parserPanel);
parserPanel.setSize(900, 700);
parserPanel.setPreferredSize(new java.awt.Dimension(900, 700));
parseErrors = new JTextArea();
parseErrors.setText(errors.toString());
JScrollPane sp = new JScrollPane(parseErrors);
sp.setPreferredSize(new java.awt.Dimension(900, 700));
parserPanel.add(sp);
}
this.setSize(900, 800);
} catch (Exception e) {
// Silently ignoring errors
}
}
}
/**
* SNAC Reconciliation Example (CBW Java Example)
*
* For the full license, see the LICENSE file in the repository root
*
* @author Robbie Hott
* @license http://opensource.org/licenses/BSD-3-Clause BSD 3-Clause
* @copyright 2017 the Rector and Visitors of the University of Virginia, and
* the Regents of the University of California
*/
import java.io.BufferedInputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Base64;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.swing.SwingWorker;
import org.json.JSONException;
import org.json.JSONObject;
/**
* CBW Reconcile Worker
*
* This class does the actual work of connecting to SNAC and requesting for reconciliation.
* It also handles the result from the server (JSON) and parses the data into a CSV.
*
* @author Robbie Hott
*
*/
public class SNACJavaParserWorker extends SwingWorker<Void, Void> {
/**
* Filenames to use
*/
private String fromFile;
private String toFile;
private Boolean displayResult;
/**
* Progress of the reconciliation
*/
double progress;
/**
* Where the application is currently looking
*/
String progressText;
/**
* Constructor
*
* Create a new worker using the given from and to filenames.
*
* @param from CSV file to read from
* @param to CSV file to write to
*/
public SNACJavaParserWorker (String from, String to, Boolean displayResult) {
fromFile = from;
toFile = to;
progress = 0.0;
progressText = "";
this.displayResult = displayResult;
}
/**
* Background worker
*
* SwingWorker calls this method when it spawns the new worker thread. This method
* then calls the actual reconcile method to perform the reconcilation.
*/
public Void doInBackground() {
try {
reconcile();
} catch (Exception e) {
// Silently ignoring errors
}
return null;
}
/**
* Set the progress text
*
* @param text String to use for the progress text
*/
private void setProgressText(String text) {
progressText = text;
}
/**
* Get progress text
*
* Returns the current progress status (what individual in the CSV file the system is currently looking at)
*
* @return The progress text
*/
public String getProgressText() {
return progressText;
}
/**
* Main Reconcile Method
*
* This method performs the heart of the client-side reconciliation process.
*
* @throws Exception
*/
private void reconcile() throws Exception {
setProgress(0);
setProgressText("Reading XML file");
String xmlContents = new String(Files.readAllBytes(Paths.get(fromFile)), StandardCharsets.UTF_8);
setProgress(10);
setProgressText("Encoding XML file");
String base64Encoded = new String(Base64.getEncoder().encode(xmlContents.getBytes()));
setProgress(20);
setProgressText("Querying SNAC-Alpha");
// Create the JSON query string for the SNAC RestAPI
String query = "{"+
"\"command\" : \"parse_eac\"," +
"\"file\" : { " +
"\"content\" : \"" + base64Encoded + "\"," +
"\"mime-type\" : \"text/xml\"" +
"}" +
"}";
//System.err.println(query);
// Perform connection to SNAC
HttpURLConnection httpcon = (HttpURLConnection) ((new URL("http://snac-dev.iath.virginia.edu/alpha/rest/").openConnection()));
httpcon.setDoOutput(true);
httpcon.setRequestProperty("Content-Type", "application/json");
httpcon.setRequestMethod("PUT");
httpcon.connect();
setProgress(50);
setProgressText("Reading response from SNAC-Alpha");
// Write the query to the RestAPI
byte[] outputBytes = query.getBytes("UTF-8");
OutputStream os = httpcon.getOutputStream();
os.write(outputBytes);
os.close();
setProgress(60);
// Read the response from the RestAPI
String resultStr = null;
try {
InputStream in = new BufferedInputStream(httpcon.getInputStream());
resultStr = org.apache.commons.io.IOUtils.toString(in, "UTF-8");
in.close();
} catch (Exception e) {
e.printStackTrace(System.err);
setProgress(99);
setProgressText("SNAC-Alpha could not parse input: Invalid XML File");
return;
}
setProgress(65);
JSONObject resultObj = null;
try {
resultObj = new JSONObject(resultStr);
} catch (JSONException je) {
setProgress(99);
setProgressText("SNAC-Alpha returned with an error");
System.err.println(resultStr);
return;
}
setProgress(70);
// Close the connection
httpcon.disconnect();
setProgress(75);
setProgressText("Parsing response from SNAC");
// If reconciliation succeeded, then process the results
// Use a pre-packaged writer to write out the CSV file
FileWriter writer = null;
if (toFile != null)
writer = new FileWriter(toFile);
if (resultObj.has("constellation") && resultObj.has("result")) {
setProgress(85);
setProgressText("Writing JSON file from SNAC");
if (writer != null)
writer.write(resultObj.getJSONObject("constellation").toString(4));
if (displayResult)
SNACInfoWindow.showWindow("Parsed Constellation" ,resultObj.getJSONObject("constellation").toString(4));
}
// Close the CSV Writer
if (writer != null)
writer.close();
// Update the progress to 100%
if (resultObj.has("result") && resultObj.getString("result").equals("success"))
progressText = "Complete";
else
progressText = "Complete -- with errors";
setProgress(100);
String errors = "";
if (resultObj.has("unparsed")) {
for (int j = 0; j < resultObj.getJSONArray("unparsed").length(); j++) {
String line = resultObj.getJSONArray("unparsed").getString(j).trim();
if (!line.isEmpty())
errors += line + "\r\n";
}
}
if (!errors.isEmpty())
SNACInfoWindow.showWindow("Parse Errors", errors);
}
}
/**
* SNAC Reconciliation Example (CBW Java Example)
*
* For the full license, see the LICENSE file in the repository root
*
* @author Robbie Hott
* @license http://opensource.org/licenses/BSD-3-Clause BSD 3-Clause
* @copyright 2017 the Rector and Visitors of the University of Virginia, and
* the Regents of the University of California
*/
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Base64;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.annotation.Nonnull;
import javax.swing.SwingWorker;
import javax.xml.transform.stream.StreamSource;
import org.json.JSONObject;
import org.oclc.purl.dsdl.svrl.FailedAssert;
import org.oclc.purl.dsdl.svrl.SchematronOutputType;
import com.helger.schematron.ISchematronResource;
import com.helger.schematron.pure.SchematronResourcePure;
import com.helger.schematron.xslt.SchematronResourceSCH;
/**
* CBW Reconcile Worker
*
* This class does the actual work of connecting to SNAC and requesting for reconciliation.
* It also handles the result from the server (JSON) and parses the data into a CSV.
*
* @author Robbie Hott
*
*/
public class SNACJavaSchematronValidator extends SwingWorker<Void, Void> {
/**
* Filenames to use
*/
private String fromFile;
private String toFile;
private Boolean displayResult;
/**
* Progress of the reconciliation
*/
double progress;
/**
* Where the application is currently looking
*/
String progressText;
/**
* Constructor
*
* Create a new worker using the given from and to filenames.
*
* @param from CSV file to read from
* @param to CSV file to write to
*/
public SNACJavaSchematronValidator (String from, String to, Boolean displayResult) {
fromFile = from;
toFile = to;
progress = 0.0;
progressText = "";
this.displayResult = displayResult;
}
/**
* Background worker
*
* SwingWorker calls this method when it spawns the new worker thread. This method
* then calls the actual reconcile method to perform the reconcilation.
*/
public Void doInBackground() {
try {
validate();
} catch (Exception e) {
// Silently ignoring errors
}
return null;
}
/**
* Set the progress text
*
* @param text String to use for the progress text
*/
private void setProgressText(String text) {
progressText = text;
}
/**
* Get progress text
*
* Returns the current progress status (what individual in the CSV file the system is currently looking at)
*
* @return The progress text
*/
public String getProgressText() {
return progressText;
}
/**
* Main Reconcile Method
*
* This method performs the heart of the client-side reconciliation process.
*
* @throws Exception
*/
private void validate() throws Exception {
setProgress(0);
setProgressText("Reading XML file");
//InputStream schematronStream = getClass().getResourceAsStream("SNAC_EAC-CPF_ValidationProfile.sch");
//File schematron = new File(SNACJavaSchematronValidator.class.getResource("SNAC_EAC-CPF_ValidationProfile.sch"));
//File schematron = new File("schematron/SNAC_EAC-CPF_ValidationProfile.sch");
File xmlFile = new File(fromFile);
// final ISchematronResource aResPure = SchematronResourcePure.fromFile (schematron);
// if (!aResPure.isValidSchematron ()) {
// FileReader r = new FileReader(schematron);
// String text = new String(Files.readAllBytes(schematron.toPath()), StandardCharsets.UTF_8);
// System.err.println(text);
// progressText = "Invalid Schematron!";
// setProgress(100);
// return;
// }
final ISchematronResource aResSCH = SchematronResourceSCH.fromClassPath("SNAC_EAC-CPF_ValidationProfile.sch");
//final ISchematronResource aResSCH = SchematronResourceSCH. .fromFile(schematron);
if (!aResSCH.isValidSchematron ()) {
//FileReader r = new FileReader(schematron);
//String text = new String(Files.readAllBytes(schematron.toPath()), StandardCharsets.UTF_8);
//System.err.println(text);
progressText = "Invalid Schematron!";
setProgress(100);
return;
}
boolean result = aResSCH.getSchematronValidity(new StreamSource(xmlFile)).isValid ();
String validationErrors = "";
SchematronOutputType sot = aResSCH.applySchematronValidationToSVRL(new StreamSource(xmlFile));
List<Object> failedAsserts = sot.getActivePatternAndFiredRuleAndFailedAssert();
for (Object object : failedAsserts) {
if (object instanceof FailedAssert) {
FailedAssert failedAssert = (FailedAssert) object;
validationErrors += failedAssert.getText() + "\r\n";
//System.out.println(failedAssert.getTest());
}
}
// FileWriter writer = null;
// if (toFile != null)
// writer = new FileWriter(toFile);
//
// if (displayResult)
// SNACJavaParserConstellationWindow.showConstellation("");
//
// // Close the CSV Writer
// if (writer != null)
// writer.close();
// Update the progress to 100%
if (result)
progressText = "Validated Successfully";
else {
SNACInfoWindow.showWindow("Validation Errors", validationErrors);
progressText = "Invalid XML File";
}
setProgress(100);
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment