有许多工具可用于根据XSD 验证XML文档 。 其中包括操作系统脚本和工具,例如xmllint ,XML编辑器和IDE,甚至是在线验证器。 由于前面提到的方法的局限性或问题,我发现拥有自己的易于使用的XML验证工具很有用。 Java使编写这样的工具变得容易,并且这篇文章演示了用Java开发简单的XML验证工具是多么容易。
本文中开发的Java工具需要JDK8。但是,可以很容易地修改简单的Java应用程序,使其可以与JDK 7或什至与JDK 5一样旧的Java版本一起使用。在大多数情况下,我尝试对需要JDK 7或JDK 8识别这些依赖关系并在Java的早期版本中提供替代方法的代码。 我这样做是为了使该工具即使在具有旧版Java的环境中也可以工作。
本文结尾讨论了本文讨论的基于Java的XML验证工具的完整代码清单。 接下来显示当讨论针对一个或多个XSD的XML验证时,该应用程序中最重要的代码行。
使用Java针对XSD验证XML的本质
final Schema schema = schemaFactory.newSchema(xsdSources);
final Validator validator = schema.newValidator();
validator.validate(new StreamSource(new File(xmlFilePathAndName)));
前面的代码清单显示了标准JDK中可用的直接方法,用于根据XSD验证XML。 通过调用javax.xml.validation.SchemaFactory.newSchema(Source []) (其中javax.xml.transform.Source对象的数组表示一个或多个XSD)来实例化javax.xml.validation.Schema的实例。 通过Schema
的newValidator()方法从Schema
实例中获取javax.xml.validation.Validator的实例。 可以将要验证的XML传递到Validator
的validate(Source)方法,以针对最初提供给使用SchemaFactory.newSchema(Source[])
创建的Schema
对象的XSD或XSD执行XML验证。
下一个代码清单包括刚刚突出显示的代码,但表示该代码所驻留的整个方法。
validateXmlAgainstXsds(String,String [])
/*** Validate provided XML against the provided XSD schema files.** @param xmlFilePathAndName Path/name of XML file to be validated;* should not be null or empty.* @param xsdFilesPathsAndNames XSDs against which to validate the XML;* should not be null or empty.*/
public static void validateXmlAgainstXsds(final String xmlFilePathAndName, final String[] xsdFilesPathsAndNames)
{if (xmlFilePathAndName == null || xmlFilePathAndName.isEmpty()){out.println("ERROR: Path/name of XML to be validated cannot be null.");return;}if (xsdFilesPathsAndNames == null || xsdFilesPathsAndNames.length < 1){out.println("ERROR: At least one XSD must be provided to validate XML against.");return;}final SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);final StreamSource[] xsdSources = generateStreamSourcesFromXsdPathsJdk8(xsdFilesPathsAndNames);try{final Schema schema = schemaFactory.newSchema(xsdSources);final Validator validator = schema.newValidator();out.println( "Validating " + xmlFilePathAndName + " against XSDs "+ Arrays.toString(xsdFilesPathsAndNames) + "...");validator.validate(new StreamSource(new File(xmlFilePathAndName)));}catch (IOException | SAXException exception) // JDK 7 multi-exception catch{out.println("ERROR: Unable to validate " + xmlFilePathAndName+ " against XSDs " + Arrays.toString(xsdFilesPathsAndNames)+ " - " + exception);}out.println("Validation process completed.");
}
validateXmlAgainstXsds(String, String[])
方法的代码清单显示了如何使用指定的架构类型( XMLConstants.W3C_XML_SCHEMA_NS_URI )获得SchemaFactory
实例。 此方法还处理在验证过程中可能引发的各种类型的异常。 正如代码中的注释所指出的那样,此方法使用了支持在单个catch
子句中捕获多个异常的JDK 7语言更改,但可以替换为单独的catch
子句或对早于JDK的代码库捕获单个更通用的异常7。
刚刚显示的方法调用了一个名为generateStreamSourcesFromXsdPathsJdk8(String[])
,下一个清单是该调用的方法。
generateStreamSourcesFromXsdPathsJdk8(String [])
/*** Generates array of StreamSource instances representing XSDs* associated with the file paths/names provided and use JDK 8* Stream API.** This method can be commented out if using a version of* Java prior to JDK 8.** @param xsdFilesPaths String representations of paths/names* of XSD files.* @return StreamSource instances representing XSDs.*/
private static StreamSource[] generateStreamSourcesFromXsdPathsJdk8(final String[] xsdFilesPaths)
{return Arrays.stream(xsdFilesPaths).map(StreamSource::new).collect(Collectors.toList()).toArray(new StreamSource[xsdFilesPaths.length]);
}
刚刚显示的方法使用JDK 8流支持,根据路径/名称字符串所指向的XSD的内容,将表示XSD文件的路径/名称的字符串数组转换为StreamSource
的实例。 在该类的完整代码清单中,还有一个不赞成使用的方法generateStreamSourcesFromXsdPathsJdk7(final String[])
,该方法可以代替基于JDK 8的Java版本上的代码使用此方法。
从命令行执行时,此单类Java应用程序最有用。 为此,定义了一个main
功能,如下面的代码清单所示。
可执行main(String [])函数
/*** Validates provided XML against provided XSD.** @param arguments XML file to be validated (first argument) and* XSD against which it should be validated (second and later* arguments).*/
public static void main(final String[] arguments)
{if (arguments.length < 2){out.println("\nUSAGE: java XmlValidator <xmlFile> <xsdFile1> ... <xsdFileN>\n");out.println("\tOrder of XSDs can be significant (place XSDs that are");out.println("\tdependent on other XSDs after those they depend on)");System.exit(-1);}// Arrays.copyOfRange requires JDK 6; see// http://stackoverflow.com/questions/7970486/porting-arrays-copyofrange-from-java-6-to-java-5// for additional details for versions of Java prior to JDK 6.final String[] schemas = Arrays.copyOfRange(arguments, 1, arguments.length);validateXmlAgainstXsds(arguments[0], schemas);
}
如果传递给可执行文件的命令行参数少于两个,则可执行文件main(String[])
打印一条使用情况语句,因为它至少希望验证XML文件的名称/路径以及要验证的XSD的名称/路径。 XML反对。
main
函数采用第一个命令行参数,并将其视为XML文件的路径/名称,然后将所有其余的command lin参数视为一个或多个XSD的路径/名称。
现在已经显示了用于针对一个或多个XSD验证XML的简单Java工具(完整的代码清单在文章底部)。 有了它,我们就可以对示例XML文件和关联的XSD运行它。 在此演示中,我使用的是Servlet 2.5 web.xml
部署描述符的非常简单的体现 。
样本有效Servlet 2.5 web.xml
<web-app xmlns="http://java.sun.com/xml/ns/javaee"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"version="2.5"> <display-name>Sample Java Servlet 2.5 Web Application</display-name>
</web-app>
刚刚显示的简单web.xml
文件对Servlet 2.5 XSD有效,并且运行此简单的基于Java的XSD验证工具的输出证明不报告任何验证错误。
使用此工具的XSD有效XML文件不会产生非常有趣的结果。 下一个代码清单显示了一个故意无效的web.xml
文件,该文件具有未在关联的Servlet 2.5 XSD中指定的“ title”元素。 代码列表后显示了输出,其中突出显示了错误消息的最重要部分。
样本无效的Servlet 2.5 web.xml(web-invalid.xml)
<web-app xmlns="http://java.sun.com/xml/ns/javaee"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"version="2.5"><display-name>Java Servlet 2.5 Web Application</display-name><title>A handy example</title>
</web-app>
如最后一个输出所示,当提供的XML无效时,在输出方面,事情会变得更加有趣。
我想在此强调一个重要的警告。 有时需要以特定顺序指定此基于Java的工具提供的XSD。 特别是,在包含其他XSD的XSD之后,应该在命令行上列出它们所包含的XSD。 换句话说,通常在命令行上提供不包含“包括”依赖项的XSD,然后再将包含它们的XSD提供给它们。
下一个代码清单用于完整的XmlValidator
类。
XmlValidator.java(完整的类列表)
package dustin.examples.xmlvalidation;import org.xml.sax.SAXException;import javax.xml.XMLConstants;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;import static java.lang.System.out;/*** Validate provided XML against the provided XSDs.*/
public class XmlValidator
{/*** Validate provided XML against the provided XSD schema files.** @param xmlFilePathAndName Path/name of XML file to be validated;* should not be null or empty.* @param xsdFilesPathsAndNames XSDs against which to validate the XML;* should not be null or empty.*/public static void validateXmlAgainstXsds(final String xmlFilePathAndName, final String[] xsdFilesPathsAndNames){if (xmlFilePathAndName == null || xmlFilePathAndName.isEmpty()){out.println("ERROR: Path/name of XML to be validated cannot be null.");return;}if (xsdFilesPathsAndNames == null || xsdFilesPathsAndNames.length < 1){out.println("ERROR: At least one XSD must be provided to validate XML against.");return;}final SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);final StreamSource[] xsdSources = generateStreamSourcesFromXsdPathsJdk8(xsdFilesPathsAndNames);try{final Schema schema = schemaFactory.newSchema(xsdSources);final Validator validator = schema.newValidator();out.println("Validating " + xmlFilePathAndName + " against XSDs "+ Arrays.toString(xsdFilesPathsAndNames) + "...");validator.validate(new StreamSource(new File(xmlFilePathAndName)));}catch (IOException | SAXException exception) // JDK 7 multi-exception catch{out.println("ERROR: Unable to validate " + xmlFilePathAndName+ " against XSDs " + Arrays.toString(xsdFilesPathsAndNames)+ " - " + exception);}out.println("Validation process completed.");}/*** Generates array of StreamSource instances representing XSDs* associated with the file paths/names provided and use JDK 8* Stream API.** This method can be commented out if using a version of* Java prior to JDK 8.** @param xsdFilesPaths String representations of paths/names* of XSD files.* @return StreamSource instances representing XSDs.*/private static StreamSource[] generateStreamSourcesFromXsdPathsJdk8(final String[] xsdFilesPaths){return Arrays.stream(xsdFilesPaths).map(StreamSource::new).collect(Collectors.toList()).toArray(new StreamSource[xsdFilesPaths.length]);}/*** Generates array of StreamSource instances representing XSDs* associated with the file paths/names provided and uses* pre-JDK 8 Java APIs.** This method can be commented out (or better yet, removed* altogether) if using JDK 8 or later.** @param xsdFilesPaths String representations of paths/names* of XSD files.* @return StreamSource instances representing XSDs.* @deprecated Use generateStreamSourcesFromXsdPathsJdk8 instead* when JDK 8 or later is available.*/@Deprecatedprivate static StreamSource[] generateStreamSourcesFromXsdPathsJdk7(final String[] xsdFilesPaths){// Diamond operator used here requires JDK 7; add type of// StreamSource to generic specification of ArrayList for// JDK 5 or JDK 6final List<StreamSource> streamSources = new ArrayList<>();for (final String xsdPath : xsdFilesPaths){streamSources.add(new StreamSource(xsdPath));}return streamSources.toArray(new StreamSource[xsdFilesPaths.length]);}/*** Validates provided XML against provided XSD.** @param arguments XML file to be validated (first argument) and* XSD against which it should be validated (second and later* arguments).*/public static void main(final String[] arguments){if (arguments.length < 2){out.println("\nUSAGE: java XmlValidator <xmlFile> <xsdFile1> ... <xsdFileN>\n");out.println("\tOrder of XSDs can be significant (place XSDs that are");out.println("\tdependent on other XSDs after those they depend on)");System.exit(-1);}// Arrays.copyOfRange requires JDK 6; see// http://stackoverflow.com/questions/7970486/porting-arrays-copyofrange-from-java-6-to-java-5// for additional details for versions of Java prior to JDK 6.final String[] schemas = Arrays.copyOfRange(arguments, 1, arguments.length);validateXmlAgainstXsds(arguments[0], schemas);}
}
尽管这篇文章的篇幅最初可能暗示了多少,但使用Java来针对XSD验证XML还是相当简单的。 此处显示和解释的示例应用程序试图证明这一点,并且是针对指定XSD对XML文档进行简单命令行验证的有用工具。 可以轻松地将其移植到Groovy,以使其更加脚本友好。 如前所述,这个简单的工具需要当前编写的JDK 8,但是可以很容易地改编为在JDK 5,JDK 6或JDK 7上运行。
翻译自: https://www.javacodegeeks.com/2015/03/validating-xml-against-xsds-in-java.html