针对Java中的XSD验证XML

有许多工具可用于根据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反对。

javaXsdValidationToolUsage

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验证工具的输出证明不报告任何验证错误。

validWebXml25ShowsNoValidationErrors

使用此工具的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>

invalidWebXml25ShowsValidationErrors

如最后一个输出所示,当提供的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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/360841.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

细学PHP 09 MySql

1:mysql是什么&#xff1f;答&#xff1a;mysql是一种开源的&#xff0c;小型的数据库和&#xff30;&#xff28;&#xff30;结合的非常紧密 比较流行的LAMP组合 指 linux apache mysql php 2:我怎么样用Mysql&#xff1f;答&#xff1a;下载mysql并安装&#xff0c;装完之后…

修改 this 指向

文章目录前言一、new关键字改变this指向二、 call&#xff08;&#xff09;三、apply&#xff08;&#xff09;四 、bind&#xff08;&#xff09;五、总结前言 修改 this 指向,四种方法 一、new关键字改变this指向 //构造函数版this function Fn(){this.user "追梦子…

默认方法和多重继承

最近卢卡斯JOOQ埃德尔发布和文章有关嵌套类及其使用。 这是一个有趣的话题&#xff0c;他的文章一如既往地有趣并且值得一读。 我只同意一个简短的声明&#xff0c;我们有一个简短的回复链&#xff0c;导致默认方法&#xff0c;以及为什么不能有类似的东西 class Outer {<n…

uniapp uni.request GET方式请求,不能直接传数组解决方法

这里写目录标题目录遇到的问题 GET请求方法传数组解决方案目录 遇到的问题 GET请求方法传数组 想传一个数组&#xff0c;但是后台接受到的数据与浏览器中显示的数据和前台代码传的不一样&#xff1b; 前台代码打印 浏览器显示数据 其中HerbalNameList &#xff0c;变成了字…

休眠CascadeType.LOCK陷阱

介绍 引入了Hibernate 显式锁定支持以及Cascade Types之后 &#xff0c;就该分析CascadeType.LOCK行为了。 休眠锁定请求触发内部LockEvent 。 关联的DefaultLockEventListener可以将锁定请求级联到锁定实体子级。 由于CascadeType.ALL也包括CascadeType.LOCK &#xff0c;因…

c++中在堆和栈中申请空间的差别

堆中和栈中申请的空间的比较, 我找到了下面的比较: 栈的情况&#xff1a;栈上分配空间的好处是快&#xff0c;而且对象生存期是自动的&#xff0c;离开当前域之后就自动析构回收。坏处就是栈空间有限&#xff0c;而且不能人为控制对象的生存期&#xff0c;比如你无法将一个函数…

推销自己的海盗猫王运营商

因此&#xff0c;Java没有Elvis运算符&#xff08;或者更正式的名称是null合并运算符或null安全成员选择&#xff09;……虽然我个人不太在意它&#xff0c;但有些人似乎很喜欢它。 当一位同事需要几天后&#xff0c;我坐下来探讨了我们的选择。 而且你知道什么&#xff01; 您…

sunos 查cpu主频指令prtdiag

sun查cpu主频指令 usr/sbin/psrinfo -v ...虚拟处理器 63 在下列时间的状态&#xff1a;09/10/2013 14:23:52自 04/08/2013 17:41:40 开始已在运行。sparcv9 处理器以 2660 MHz 运行,而且有 sparcv9 浮点数处理器 sun的prtdiag指令: 查cpu个数 bash-3.2$ uname -a SunOS m5000…

使用CDI简化JAX-RS缓存

这篇文章&#xff08;通过一个简单的示例&#xff09;说明了如何使用CDI Producers使其在RESTful服务中利用缓存控制语义更加容易 与HTTP 1.0中可用的Expires标头相比&#xff0c; HTTP 1.1中添加了Cache-Control标头&#xff0c;这是急需的改进。 RESTful Web服务可以利用此标…

字符串字符和数字分割

现在有个String类型的字符串&#xff1a; String str"AA120"; 我想把它分解成 AA &#xff1b;120 就是把数字和字母分开&#xff1b; 求方法 补充&#xff1a; 格式是前面是字母 不确定几位&#xff0c;后面是数字&#xff0c;也不确定几位 就是"AA111…

transform限制position:fixed的跟随效果

我们应该都知道&#xff0c;position:fixed可以让元素不跟随浏览器的滚动条滚动&#xff0c;而且这种跟随效果连它的兄弟们position:relative/absolute都限制不了。但是&#xff0c;真是一物降一物&#xff0c;position:fixed固定效果却被小小的transform给干掉了&#xff0c;直…

Maven提示:有关可执行jar的所有信息

Maven提示&#xff1a;有关可执行jar的所有信息 在分发代码时&#xff0c;可执行jar是非常有用的工具。 这意味着&#xff0c;只要将Java安装在客户端计算机上&#xff0c;至少在Windows和Mac上&#xff0c;您的用户只需双击jar即可启动程序。 另外&#xff0c;在命令行上&…

C# 查询一张表的数据用于补充另外一张表的数据 MySQL数据库

UPDATE bookhistory bh set bh.CategoryId (SELECT CategoryId FROM booklist bk where bk.Id bh.BookListId)

Gentoo man手册指南

转载&#xff1a;http://www.gentoo.org/doc/zh_cn/man-guide.xml#doc_chap2 http://blog.csdn.net/andyelvis/article/details/4044938 使用man命令技巧 Gentoo man手册指南 内容: 1. 简介2. 使用man结构 1. 简介 man程序 每一个人在他的linux人生中都使用…

Java 8 Lambda表达式教程

问候&#xff01; :) 离开几个月后&#xff0c;我决定恢复风格:)。 我注意到我以前有关新的Date / Time API的一篇文章非常受欢迎&#xff0c;因此这次我将把本篇文章专门介绍Java 8的另一个新功能&#xff1a; Lambda Expressions 。 功能编程 Lambda表达式是Java编程语言最…

React 父组件(hooks)调用子组件(calss)方法

父组件&#xff08;hooks&#xff09; let richTextRef {};<RichText getRichText{getRichText} content{content} onRef{ref > richTextRef ref} />子组件&#xff08;class&#xff09; componentDidMount () > {this.props.onRef && this.props.onRe…

[HDU] 2553 N皇后问题-简单深搜

题目链接&#xff1a; http://acm.hdu.edu.cn/showproblem.php?pid2553 方法&#xff1a; 1.可以用对称的思想&#xff0c;即&#xff1a;如果N是偶数&#xff0c;则只计算第一个皇后分别放在第一行的位置1到N/2这N/2个情况的结果和&#xff0c;最后再乘以2。如果是奇数&#…

您真的了解@WebService吗?

SOAP Web服务无论如何都不是最先进的技术-尽管它仍然存在&#xff0c;但是基于REST的Web服务却提供了激烈的竞争。 无论如何–这绝对不是REST vs SOAP帖子&#xff01; 我观察到了一些实例&#xff0c;至少可以说&#xff0c;使用基于Java的SOAP Web服务的方式不太理想。 我认…

全局使用dva dispatch

// 第一种 这个umi2还可以 umi3就不可以了 window.g_app._store.dispatch({type: login/logout,});// 第二种 调用dispatch(所有models都可以) getDvaApp()._store.dispatch({type: login/logout,});