是否可以获取XML节点在XSD中定义的类型?
我正在用Python解析一个XML文件,并且有一个XSD模式来验证这个XML。请问我能否获取XML中特定节点的类型,正如它在XSD中定义的那样?
比如,我的XML(只是一小部分)是:
<deviceDescription>
<wakeupNote>
<lang xml:lang="ru">Русский</lang>
<lang xml:lang="en">English</lang>
</wakeupNote>
</deviceDescription>
我的XSD也是(同样只是一小部分):
<xsd:element name="deviceDescription" type="zwv:deviceDescription" minOccurs="0"/>
<xsd:complexType name="deviceDescription">
<xsd:sequence>
<xsd:element name="wakeupNote" type="zwv:description" minOccurs="0">
<xsd:unique name="langDescrUnique">
<xsd:selector xpath="zwv:lang"/>
<xsd:field xpath="@xml:lang"/>
</xsd:unique>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="description">
<xsd:sequence>
<xsd:element name="lang" maxOccurs="unbounded">
<xsd:complexType>
<xsd:simpleContent>
<xsd:extension base="xsd:string">
<xsd:attribute ref="xml:lang" use="required"/>
</xsd:extension>
</xsd:simpleContent>
</xsd:complexType>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
在解析过程中,我想知道我的标签 wakeupNote 在XSD中是定义为 complexType zwv:description。我该如何在Python中做到这一点呢?
我为什么需要这个呢?假设我有很多这样的XML文件,我想检查它们是否都有用英语填写的字段。检查 <lang xml:lang="en"></lang>
是否为空是很简单的,但实际上这个标签可以根本不出现。
所以我的想法是获取所有可能有语言描述的标签,并检查 <lang>
标签是否存在,并且内容不为空,特别是对于 en。
更新
因为在验证过程中,我的XML会根据XSD进行检查,所以验证引擎知道所有节点的类型。七个月前我有过类似的问题,但至今没有答案。我觉得这两个问题是相关的。 基于XSD在Python中验证和填充XML的默认值
2 个回答
你说得对,验证器必须了解它所验证的所有元素和属性的类型关系,因此它能够提供这些信息。
不过,无论好坏,调用者和验证器之间的接口,以及调用者可以获取的验证相关信息,都是由具体的实现决定的。有些验证器(比如Xerces J)提供了非常全面的验证信息,而有些则没有。
如果不知道你使用的是哪个验证器,就没人能确定你想要的类型信息是否可用。既然你在调用验证器,说明一定有一个接口;如果通过这个接口可以获取类型关系,文档里应该会说明。如果接口不提供这些信息,可能是因为底层的模式验证器不提供,或者是接口的创建者觉得没必要;如果你想深入了解,就需要找出是哪种情况,然后试着说服相关方,让他们觉得提供这些信息是有用的。
如果通过接口获取信息不成功,你可以尝试另一种更复杂的方法,参考David W.提到的内容。XSD模式的一个特点是,任何元素的主导类型完全取决于从验证根到该元素的路径。因此,原则上(尽管在实际操作中可能有点繁琐)可以很简单地确定文档实例中任何元素的主导类型,前提是该文档实例是根据特定的模式进行验证的。比如你提到的情况,可以很容易判断某个
以这种方式自助可能需要相当多的工作。如果有通用工具可以计算这些信息并以各种形式提供,那会更好,但我不知道是否有这样的工具。(我确实认识一些人可以收费制作这样的工具。)所以如果我是你,我会先尝试通过接口获取信息。
如果问题是:我怎么找到一个给定XML节点的类型名称?那么答案就是使用Python中的xpath来查找。要在xsd上运行的xpath是
//element[@name='wakeupNote']/@type
这应该会返回zwv:description。如果返回了两个类型,你就得从根节点开始查找。
/root/foo/wakeupNote (type A)
/root/bar/wakeupNote (type B)
从根节点开始查找会比较麻烦。你需要寻找匿名类型和命名类型。
如果问题是:我怎么找到所有给定类型的XML节点?如果模式会经常变化,你可以在解析每个节点时用上面的方法来测试每个节点的类型。
如果模式是固定的,并且你要找的节点可以用XPATH找到,你就可以测试每个节点。
//@xml:lang='en'
然后用Python检查每个节点的长度。
在模式稳定的情况下,你可以写一个第二个XSD来强制执行你想要的标准。