是否可以获取XML节点在XSD中定义的类型?

4 投票
2 回答
1779 浏览
提问于 2025-04-16 10:37

我正在用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 个回答

0

你说得对,验证器必须了解它所验证的所有元素和属性的类型关系,因此它能够提供这些信息。

不过,无论好坏,调用者和验证器之间的接口,以及调用者可以获取的验证相关信息,都是由具体的实现决定的。有些验证器(比如Xerces J)提供了非常全面的验证信息,而有些则没有。

如果不知道你使用的是哪个验证器,就没人能确定你想要的类型信息是否可用。既然你在调用验证器,说明一定有一个接口;如果通过这个接口可以获取类型关系,文档里应该会说明。如果接口不提供这些信息,可能是因为底层的模式验证器不提供,或者是接口的创建者觉得没必要;如果你想深入了解,就需要找出是哪种情况,然后试着说服相关方,让他们觉得提供这些信息是有用的。

如果通过接口获取信息不成功,你可以尝试另一种更复杂的方法,参考David W.提到的内容。XSD模式的一个特点是,任何元素的主导类型完全取决于从验证根到该元素的路径。因此,原则上(尽管在实际操作中可能有点繁琐)可以很简单地确定文档实例中任何元素的主导类型,前提是该文档实例是根据特定的模式进行验证的。比如你提到的情况,可以很容易判断某个元素是否有作为祖先,或者如果同时有这两个祖先,哪个是更近的祖先,并根据这些信息推断出合适的主导类型定义。

以这种方式自助可能需要相当多的工作。如果有通用工具可以计算这些信息并以各种形式提供,那会更好,但我不知道是否有这样的工具。(我确实认识一些人可以收费制作这样的工具。)所以如果我是你,我会先尝试通过接口获取信息。

0

如果问题是:我怎么找到一个给定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来强制执行你想要的标准。

撰写回答