对多个xsd模式进行XML验证

5
我正在编写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>的内容有一些受控词汇,我可以处理那一部分。然后,根据bar的值,应该使用适当的xml模式来验证bar-config的内容。baz和baz-config同理。
执行解析/验证的代码是用Java编写的。不确定解决方案是否与语言相关。
理想情况下,解决方案将允许xml作者声明适当的模式位置等,以便他/她可以在足够智能的编辑器中即时验证xml。
此外,<bar><baz>的可能值是正交的,因此我不想为每个可能的bar/baz组合都进行扩展。我的意思是,如果有24个可能的bar值/模式和8个可能的baz值/模式,则我想能够编写1 + 24 + 8 = 33个总模式,而不是1 * 24 * 8 = 192个总模式。
此外,如果可能的话,我更喜欢不将bar-config和baz-config拆分为单独的xml文件。我意识到这可能会使所有问题变得容易,因为每个xml文件都将有一个单独的模式,但我正在尝试看是否有一个良好的单个xml文件解决方案。
4个回答

7

我终于弄清楚了。

首先,在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>

接下来,bar Alpha 的 XML schema 文件将具有目标命名空间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. 仅使用主(foo)模式验证xml
  2. 确定用于验证文档部分的模式
  3. 使用单独的模式查找作为验证部分根的节点
  4. 将该节点导入全新的文档
  5. 使用其他模式文件验证全新文档
注意:似乎必须使文档支持命名空间才能正常工作。 以下是一些代码(这些代码从我的代码的各个地方复制而来,因此可能存在一些错误):
// 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));

它对我不起作用。解决方案-> https://stackoverflow.com/questions/61483586/validating-xml-against-multiple-xsdstored-as-resources-spring-boot/61483587#61483587 - lalilulelo_1986

3

1
忘了提到,如果您的模式是不同类型的(XSD、RNG 和 DTD),这也很好。 - ksclarke

1

您需要为实例文档中每个单独验证的部分定义目标命名空间。然后,您定义一个主模式,使用<xsd:include>引用这些组件的模式文档。

这种方法的限制是,您不能让各个组件定义应用于验证它们的模式。但通常情况下,让文档告诉您如何验证它是一个坏主意(即,验证应该由您的应用程序控制)。


0
您也可以使用“资源解析器”来允许“XML作者”在某种程度上指定自己的架构文件,例如:https://dev59.com/BHVD5IYBdhLWcg3wVKAb#41225329无论如何,最终你需要一个完全符合规范的XML文件,可以使用普通工具进行验证 :)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接