要针对多个xsd架构验证XML

时间:2010-04-12 19:24:03

标签: java xml xsd

我正在编写xsd和要验证的代码,所以我在这里有很好的控制权。

我想有一个上传工具,可以根据xml文件向我的应用程序添加内容。应根据其他部分中的某个值,针对不同的模式验证xml文件的一部分。这是一个例子来说明:

<foo>
  <name>Harold</name>
  <bar>Alpha</bar>
  <baz>Mercury</baz>
  <!-- ... more general info that applies to all foos ... -->

  <bar-config>
    <!-- the content here is specific to the bar named "Alpha" -->
  </bar-config>
  <baz-config>
    <!-- the content here is specific to the baz named "Mercury" -->
  </baz>
</foo>

在这种情况下,<bar>的内容有一些受控词汇表,我可以很好地处理这部分内容。然后,根据条形值,应使用适当的xml架构来验证bar-config的内容。同样适用于baz和baz-config。

执行解析/验证的代码是用Java编写的。不确定解决方案的语言依赖性。

理想情况下,该解决方案将允许xml作者声明适当的模式位置以及不是什么,以便他/她可以在足够智能的编辑器中动态验证xml。

此外,<bar><baz>的可能值是正交的,因此我不希望通过扩展为每个可能的bar / baz组合执行此操作。我的意思是,如果有24个可能的条形值/模式和8个可能的baz值/模式,我希望能够写出1 + 24 + 8 = 33个总模式,而不是1 * 24 * 8 = 192个模式

另外,如果可能的话,我宁愿不将bar-config和baz-config分解为单独的xml文件。我意识到这可能会使所有问题变得更容易,因为每个xml文件都有一个模式,但我正在尝试查看是否有一个好的单xml文件解决方案。

4 个答案:

答案 0 :(得分:6)

我终于想通了。

首先,在foo架构中,bar-config和baz-config元素的类型包含any元素,如下所示:

<sequence>
    <any minOccurs="0" maxOccurs="1"
        processContents="lax" namespace="##any" />
</sequence>

在xml中,您必须使用bar-config或baz-config的子元素上的xmlns属性指定正确的命名空间,如下所示:

<bar-config>
    <config xmlns="http://www.example.org/bar/Alpha">
        ... config xml here ...
    </config>
</bar-config>

然后,条形Alpha的XML模式文件将具有http://www.example.org/bar/Alpha的目标名称空间,并将定义根元素config

如果您的XML文件具有两个模式文件的名称空间声明和模式位置,那么编辑器就可以完成所有验证(至少对Eclipse来说足够好)。

到目前为止,我们已经满足了xml作者可能以在编辑器中验证它的方式编写xml的要求。

现在,我们需要消费者能够验证。就我而言,我正在使用Java。

如果有可能,您知道需要提前验证的架构文件,那么您只需创建一个Schema对象并照常验证,如下所示:

Schema schema = factory().newSchema(new Source[] {
    new StreamSource(stream("foo.xsd")),
    new StreamSource(stream("Alpha.xsd")),
    new StreamSource(stream("Mercury.xsd")),
});

但是,在这种情况下,在解析主文档之前,我们不知道要使用哪些xsd文件。因此,一般程序是:

  1. 仅使用main(foo)架构
  2. 验证xml
  3. 确定用于验证文档部分的架构
  4. 使用单独的架构
  5. 查找要验证的部分的根节点
  6. 将该节点导入全新文档
  7. 使用其他模式文件验证全新文档
  8. 警告:看来文档必须构建为名称空间,才能使其正常工作。

    这是一些代码(这是从我的代码的各个地方撕掉的,因此复制粘贴可能会引入一些错误):

    // Contains the filename of the xml file
    String filename;
    
    // Load the xml data using a namespace-aware builder (the method 
    // 'stream' simply opens an input stream on a file)
    Document document;
    DocumentBuilderFactory docBuilderFactory =
        DocumentBuilderFactory.newInstance();
    docBuilderFactory.setNamespaceAware(true);
    document = docBuilderFactory.newDocumentBuilder().parse(stream(filename));
    
    // Create the schema factory
    SchemaFactory sFactory = SchemaFactory.newInstance(
        XMLConstants.W3C_XML_SCHEMA_NS_URI);
    
    // Load the main schema
    Schema schema = sFactory.newSchema(
        new StreamSource(stream("foo.xsd")));
    
    // Validate using main schema
    schema.newValidator().validate(new DOMSource(document));
    
    // Get the node that is the root for the portion you want to validate
    // using another schema
    Node node= getSpecialNode(document);
    
    // Build a Document from that node
    Document subDocument = docBuilderFactory.newDocumentBuilder().newDocument();
    subDocument.appendChild(subDocument.importNode(node, true));
    
    // Determine the schema to use using your own logic
    Schema subSchema = parseAndDetermineSchema(document);
    
    // Validate using other schema
    subSchema.newValidator().validate(new DOMSource(subDocument));
    

答案 1 :(得分:2)

看看NVDL(基于命名空间的验证调度语言) - http://www.nvdl.org/

它旨在执行您想要执行的操作(验证具有自己的命名空间和模式的XML文档的各个部分)。

这里有一个教程 - http://www.dpawson.co.uk/nvdl/ - 以及这里的Java实现 - http://jnvdl.sourceforge.net/

希望有所帮助! 凯文

答案 2 :(得分:0)

您需要为实例文档的每个单独验证的部分定义目标命名空间。然后定义master schema使用<xsd:include>来引用这些组件的架构文档。

此方法的局限性在于您不能让各个组件定义应该用于验证它们的模式。但是一般来说让文档告诉你如何验证它是一个坏主意(即,验证应该是你的应用程序控制的东西)。

答案 3 :(得分:0)

您还可以使用“资源解析器”来允许“ xml作者”指定他们自己的架构文件,至少在某种程度上,例如:https://stackoverflow.com/a/41225329/32453最后,您希望完全兼容可以使用常规工具验证的xml文件:)