关于xsd:解决验证XML子元素的问题

work around for validating XML child elements

基本上,我的问题是是否有方法根据给定的XSD模式验证非根元素。

我目前正在研究一些遗留代码,我们有一些C++类,它们以字符串格式生成XML元素。

我正在考虑通过验证生成的XML(我在引擎盖下使用XeCES C++)来对这些类进行单元测试的方法。问题是我不能引用来自不同于根目录的另一个模式的元素。

这是对我所做工作的更详细描述:

我有一个名为boogenerator的类,它生成"foo.xsd"中定义的"booisotrot"元素。请注意,"boo"不是根元素:-)

我创建了一个test.xsd模式,它以以下方式引用"booisotrot":

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?xml version="1.0" encoding="utf-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
           xmlns="http://acme/2014/test"
           xmlns:foo="http://acme/2014/foo"
           targetNamespace="http://acme/2014/test"
           elementFormDefault="qualified">
  <xsd:import namespace="http://acme/2014/foo" schemaLocation="foo.xsd"/>
  <xsd:complexType name="TestType">
    <xsd:choice minOccurs="1" maxOccurs="1">
      <xsd:element ref="foo:booIsNotRoot"/>
    </xsd:choice>
  </xsd:complexType>
  <xsd:element name="test" type="TestType"/>
</xsd:schema>

然后我用测试元素包装boogenerator生成的字符串:

1
2
3
4
5
6
<test xmlns="xmlns="http://acme/2014/test"
      xmlns:xsi="
http://www.w3.org/2001/XMLSchema-instance"
      xmlns:foo="
http://acme/2014/foo
      xsi:schemaLocation="http://acme/2014/test test.xsd">
  (code generated by BooGenerator prefixed with 'foo')
</test>

但正如我之前所说,它不起作用。如果我引用foo.xsd中的根元素,它就会工作。所以我想知道是否有办法解决这个问题。

事先谢谢。


是的,这是完全可能的。XSD验证被定义为从XML文档中的某个节点开始并对其进行验证(通常需要验证其所有子代),因此根据指定的元素声明或类型定义验证特定元素的请求是完全一致的。

如何将这样的请求传递给XSD验证器是特定于实现的(并且XSD没有规定特定的API或命令行接口,因此符合要求的XSD验证器没有义务支持启动XSD规范第5.2节中定义的验证事件的所有方法);您必须咨询实施者Tation的文件。我认为支持这种验证的最常见方法是调用实现的XSD库中的一个方法,使用适当的XML元素、模式和类型定义或元素声明对象。我没有看到任何与XSD验证器的命令行接口支持在根目录之外的其他地方启动验证。


1
2
Basically my question is whether or not there is way to validate a non-root
element according to a given XSD schema.

理论上讲,是的,第5.2节评估XSD建议的模式有效性允许非根元素有效性评估。(感谢C.M.Sperberg McQueen指出这一点。)

实际上,不,不是直接的。XML模式工具倾向于针对未选择的XML文档进行验证,单个元素和XML文档必须具有单个根元素。也许您可以将希望验证的元素嵌入到一个装配上下文中,该上下文模拟元素的祖先,直到文档的正确根元素为止。

If I reference the root element in foo.xsd it works.

实际上,foo.xsd中的根元素最好是xsd:schema。你可能想说

If I reference an element defined globally (under xsd:schema) in foo.xsd it works.

这也是在XML模式中定义@ref的方式;它不能引用本地定义的元素,如foo:booIsNotRoot。此外,任何全局定义的元素都可以作为根元素。(实际上,只有全局定义的元素才能用作根元素。)

因此,您的选择包括:

  • 在有效的上下文中测试目标元素。
  • 使目标元素在其xsd中全局定义。
  • 确定到您的XSD验证器的特定于实现的接口提供元素级验证。