通过PyXB由Python生成的XML无法针对XSD文件进行验证:如何生成以及如何进行验证?

时间:2019-05-27 12:11:58

标签: python xml xsd

我正在学习如何使用XML架构文档来生成符合所述架构的XML文件。

我已经了解了PyXB来为XML模式定义的数据结构生成Python绑定。

This SO post给出了一个“端到端”示例,说明如何生成符合给定XML模式的XML文件。为了提供信息,the post帮助在以下两个链接中摘要信息:

这两个链接都很好地解释了如何使用绑定来生成所需的XML文件。

这是使用的XSD文件:

  <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <xsd:element name="purchaseOrder" type="PurchaseOrderType"/>
  <xsd:element name="comment" type="xsd:string"/>
  <xsd:complexType name="PurchaseOrderType">
    <xsd:sequence>
      <xsd:element name="shipTo" type="USAddress"/>
      <xsd:element name="billTo" type="USAddress"/>
      <xsd:element ref="comment" minOccurs="0"/>
      <xsd:element name="items"  type="Items"/>
    </xsd:sequence>
    <xsd:attribute name="orderDate" type="xsd:date"/>
  </xsd:complexType>
  <xsd:complexType name="USAddress">
    <xsd:sequence>
      <xsd:element name="name"   type="xsd:string"/>
      <xsd:element name="street" type="xsd:string"/>
      <xsd:element name="city"   type="xsd:string"/>
      <xsd:element name="state"  type="xsd:string"/>
      <xsd:element name="zip"    type="xsd:decimal"/>
    </xsd:sequence>
    <xsd:attribute name="country" type="xsd:NMTOKEN" fixed="US"/>
  </xsd:complexType>
  <xsd:complexType name="Items">
    <xsd:sequence>
      <xsd:element name="item" minOccurs="0" maxOccurs="unbounded">
        <xsd:complexType>
          <xsd:sequence>
            <xsd:element name="productName" type="xsd:string"/>
            <xsd:element name="quantity">
              <xsd:simpleType>
                <xsd:restriction base="xsd:positiveInteger">
                  <xsd:maxExclusive value="100"/>
                </xsd:restriction>
              </xsd:simpleType>
            </xsd:element>
            <xsd:element name="USPrice"  type="xsd:decimal"/>
            <xsd:element ref="comment"   minOccurs="0"/>
            <xsd:element name="shipDate" type="xsd:date" minOccurs="0"/>
          </xsd:sequence>
          <xsd:attribute name="partNum" type="SKU" use="required"/>
        </xsd:complexType>
      </xsd:element>
    </xsd:sequence>
  </xsd:complexType>
  <!-- Stock Keeping Unit, a code for identifying products -->
  <xsd:simpleType name="SKU">
    <xsd:restriction base="xsd:string">
      <xsd:pattern value="\d{3}-[A-Z]{2}"/>
    </xsd:restriction>
  </xsd:simpleType>
</xsd:schema>

这是我用来生成Python绑定的命令:

pyxbgen -u po1.xsd -m po1

此命令生成一个po1.py文件,该文件随后可用于生成XML文档,如下所示(demo2.py的内容):

from __future__ import print_function
import po1 as address

addr = address.USAddress()
addr.name = 'Robert Smith'
addr.street = '8 Oak Avenue'
addr.city = 'Anytown'
addr.state = 'AK'
addr.zip = 12341

with open('demo2.xml', 'w') as f:
    f.write(addr.toxml("utf-8", element_name='USAddress').decode('utf-8'))

执行此代码将产生以下格式良好的XML文件(demo2.xml):

<?xml version="1.0" encoding="utf-8"?>
<USAddress>
    <name>Robert Smith</name>
    <street>8 Oak Avenue</street>
    <city>Anytown</city>
    <state>AK</state>
    <zip>12341.0</zip>
</USAddress>

实际问题:

  1. 如何根据以下内容自动验证生成的XML文件 使用的XSD架构?
  2. 为什么(使用this validator) 生成的XML文件(demo2.xml)无法针对 XML模式?具体来说,我收到以下错误:Not valid. Error - Line 1, 50: org.xml.sax.SAXParseException; lineNumber: 1; columnNumber: 50; cvc-elt.1.a: Cannot find the declaration of element 'USAddress'.
  3. 我应该考虑添加哪些修改 demo2.py生成确实通过验证的XML文件 模式?

1 个答案:

答案 0 :(得分:0)

经过更多阅读后,我意识到使用Python绑定不能保证所生成的XML文档符合该模式。

答案2和3的一部分:

在这种情况下,验证失败,因为Python代码实际上是针对给定的架构构造了一个无效的XML文档。考虑一对简单得多的XSD-XML文件:

简单的XSD:

<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:element name="a" type="AType"/>
<xsd:complexType name="AType">
  <xsd:sequence>
    <xsd:element name="b" type="xsd:string" />
  </xsd:sequence>
</xsd:complexType>
</xsd:schema>

使用为架构生成的绑定的简单Python代码:

from __future__ import print_function
import po2

hey = po2.AType()
hey.b = "Eduardo"

with open('demo4.xml', 'w') as f:
    f.write(hey.toxml("utf-8", element_name='a').decode('utf-8'))

执行Python代码时,会生成以下XML:

<?xml version="1.0" encoding="utf-8"?>
<a><b>Eduardo</b></a>

在原始情况下(USAddress),原始架构为DOM提供了一个根类型,而不是USAddress类型。但是,Python代码忽略了这一点,直接使用这种类型的实例来生成XML文件。生成的XML确实格式正确,但是不符合架构。在这里描述的简单得多的情况下,不仅XML有效,而且使用Python绑定还可以生成符合XSD模式的XML文件。

答案1:

您可以使用提供的here说明,针对给定的XSD模式自动验证生成的文件。

from lxml import etree
from StringIO import StringIO

# Check https://lxml.de/validation.html

f = StringIO('''\
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:element name="a" type="AType"/>
<xsd:complexType name="AType">
  <xsd:sequence>
    <xsd:element name="b" type="xsd:string" />
  </xsd:sequence>
</xsd:complexType>
</xsd:schema>
''')
xmlschema_doc = etree.parse(f)
xmlschema = etree.XMLSchema(xmlschema_doc)

valid = StringIO('''\
<?xml version="1.0" encoding="utf-8"?>
<a><b>Eduardo</b></a>
''')
doc = etree.parse(valid)

print('Is XML is valid?', xmlschema.validate(doc))