如何使用lxml验证XSD架构,但忽略与给定模式匹配的元素?

时间:2016-12-21 16:42:44

标签: python xml xsd lxml xsd-validation

可以使用lxml来针对给定的XSD架构验证XML文件。

有没有办法在严格意义上应用此验证,忽略包含特殊表达式的所有元素?

请考虑以下示例:说,我有一个 xml_file

<foo>99</foo>
<foo>{{var1}}</foo>
<foo>{{var2}}</foo>
<foo>999</foo>

现在,我在这个文件上运行一个程序,它取代{{...}} - 表达式并生成一个新文件:

xml_file_new

<foo>99</foo>
<foo>23</foo>
<foo>42</foo>
<foo>999</foo>

到目前为止,我可以使用lxml来验证新的XML文件,如下所示:

from lxml import etree
xml_root = etree.parse(xml_file_new)
xsd_root = etree.parse(xsd_file)
schema = etree.XMLSchema(xsd_root)
schema.validate(xml_root)

我的示例中的相关点是架构将<foo>内容限制为整数。

不可能提前在旧的xml_file上应用架构,但是,由于我的程序执行了一些其他昂贵的任务,我希望在忽略包含任何{{1 }} - 表达式:

{{...}}

编辑:可能的解决方案方法:一个想法是定义两个架构

  • 新文件的严格第二个架构,仅允许整数
  • 旧文件的宽松模式,允许整数和任意字符串<foo>99</foo> <!-- should be checked--> <foo>{{var1}}</foo> <!-- should be ignored --> <foo>{{var2}}</foo> <!-- should be ignored --> <foo>999</foo> <!-- should be checked--> - 表达式

但是,为了避免保持两个模式同步的冗余任务,需要一种方法来自动从严格模式生成松弛。这听起来很有希望,因为两个模式具有相同的结构,只是在某些元素内容的限制方面有所不同。是否有一个简单的概念由XSD提供,它允许从一个模式“继承”,然后“附加”额外的松弛到个别元素?

2 个答案:

答案 0 :(得分:1)

要回答编辑过的问题,可以使用xs:inlcude(和xs:import)机制组合模式。这样,您可以在公共模式中声明公共部分以供重用,并使用专用模式进行专门的类型定义,如下所示:

描述结构的通用架构。 请注意,它使用FooType,但未定义它:

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">

  <!-- Example structure -->
  <xs:element name="root">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="foo" type="FooType" maxOccurs="unbounded"/>
      </xs:sequence>
    </xs:complexType>
  </xs:element>

</xs:schema>

要在替换之前验证的宽松架构。 它包括来自通用模式的组件, 并定义了一个轻松的FooType

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">

  <xs:include schemaLocation="common.xsd"/>

  <xs:simpleType name="FooType">
    <xs:union memberTypes="xs:integer">
      <xs:simpleType>
        <xs:restriction base="xs:string">
          <xs:pattern value="\{\{.*\}\}"/>
        </xs:restriction>
      </xs:simpleType>
    </xs:union>
  </xs:simpleType>

</xs:schema>

替换后验证的严格架构。它 定义FooType的严格版本:

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">

  <xs:include schemaLocation="common.xsd"/>

  <xs:simpleType name="FooType">
     <xs:restriction base="xs:integer"/>
  </xs:simpleType>

</xs:schema>

为了完成,还有其他方法可以做到这一点, 例如xs:redefine(XSD 1.0)或xs:override(XSD 1.1)。 但是这些语义更复杂,而且我个人试图避免它们。

答案 1 :(得分:0)

只是简单的XSD,我不知道有什么办法可以避免 整数类型的冗余声明。然而, 作为替代方案,您可以在Python中调整架构。

一种简单的方法是,只使用一个模式文档(默认情况下放宽):

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">

  <xs:element name="root">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="foo" type="FooType" maxOccurs="unbounded"/>
      </xs:sequence>
    </xs:complexType>
  </xs:element>

  <xs:simpleType name="FooType">
    <xs:union memberTypes="xs:integer">
      <xs:simpleType id="RELAXED">
        <xs:restriction base="xs:string">
          <xs:pattern value="\{\{.*\}\}"/>
        </xs:restriction>
      </xs:simpleType>
    </xs:union>
  </xs:simpleType>

</xs:schema>

在Python中,您只需使用id="RELAXED"删除元素即可创建严格架构:

from lxml import etree

xsd_tree = etree.parse("relaxed.xsd")
xml_tree = etree.parse("test.xml")

# Create default relaxed schema
relaxed_schema = etree.XMLSchema(xsd_tree)

# Remove RELAXED element to create strict schema
pattern = xsd_tree.find(".//*[@id='RELAXED']")
pattern.getparent().remove(pattern)
strict_schema = etree.XMLSchema(xsd_tree)

print("Relaxed:", relaxed_schema.validate(xml_tree))
print("Strict:", strict_schema.validate(xml_tree))

当然,使用Python,您可以通过多种方式实现此目的。例如,您还可以动态生成xs:union元素并将其插入严格版本的模式中。但这会变得更加复杂。

相关问题