自动XSD验证

时间:2012-03-23 17:36:06

标签: python xml lxml libxml2

根据lxml文档“DTD是根据解析文档的DOCTYPE自动检索的。您所要做的就是使用启用了DTD验证的解析器。”

http://lxml.de/validation.html#validation-at-parse-time

但是,如果要对XML架构进行验证,则需要显式引用一个。

我想知道为什么会这样,并且想知道是否有可以执行此操作的库或函数。或者甚至解释如何让自己发生这种情况。问题是似乎有很多方法可以引用XSD,我需要支持所有这些。

验证不是问题。问题是如何确定要验证的模式。理想情况下,这也会处理内联架构。

更新

这是一个例子。

simpletest.xsd:

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
  <xs:element name="name" type="xs:string"/>
</xs:schema>

simpletest.xml:

<?xml version="1.0" encoding="UTF-8" ?>
<name xmlns="http://www.example.org"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://www.example.org simpletest.xsd">foo</name>

我想做以下事情:

>>> parser = etree.XMLParser(xsd_validation=True)
>>> tree = etree.parse("simpletest.xml", parser)

2 个答案:

答案 0 :(得分:2)

我的项目有100多种不同的模式和xml树。为了管理所有这些并验证它们,我做了一些事情。

1)我创建了一个文件(即xmlTrees.py),其中我创建了每个xml的字典以及与之关联的相应模式,以及xml路径。这让我有一个地方可以同时获得xml和用于验证xml的模式。

MY_XML = {'url':'/pathToTree/myTree.xml', 'schema':'myXSD.xsd'}

2)在项目中,我们拥有同样多的名称空间(非常难以管理)。所以我又做了一次,我创建了一个单独的文件,其中包含lxml喜欢的格式的所有命名空间。然后在我的测试和脚本中,我将始终传递命名空间的超集。

ALL_NAMESPACES = {
    'namespace1':  'http://www.example.org',
    'namespace2':  'http://www.example2.org'
}

3)对于基本/通用验证,我最终创建了一个我可以调用的基本功能:

    def validateXML(content, schemaContent):

    try:
        xmlSchema_doc = etree.parse(schemaContent);
        xmlSchema = etree.XMLSchema(xmlSchema_doc);
        xml = etree.parse(StringIO(content));
    except:
        logging.critical("Could not parse schema or content to validate xml");
        response['valid'] = False;
        response['errorlog'] = "Could not parse schema or content to validate xml";

    response = {}
    # Validate the content against the schema.
    try:
        xmlSchema.assertValid(xml)
        response['valid'] = True
        response['errorlog'] = None
    except etree.DocumentInvalid, info:
        response['valid'] = False
        response['errorlog'] = xmlSchema.error_log

    return response

基本上任何想要使用它的函数都需要将xml内容和xsd内容作为字符串发送。这为我提供了最大的灵活性。然后我把这个函数放在一个文件中,我有我所有的xml帮助函数。

答案 1 :(得分:1)

您可以自己提取模式并将其导入根模式:

from lxml import etree

XSI = "http://www.w3.org/2001/XMLSchema-instance"
XS = '{http://www.w3.org/2001/XMLSchema}'


SCHEMA_TEMPLATE = """<?xml version = "1.0" encoding = "UTF-8"?>
<xs:schema xmlns="http://dummy.libxml2.validator"
targetNamespace="http://dummy.libxml2.validator"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
version="1.0"
elementFormDefault="qualified"
attributeFormDefault="unqualified">
</xs:schema>"""


def validate_XML(xml):
    """Validate an XML file represented as string. Follow all schemaLocations.

    :param xml: XML represented as string.
    :type xml: str
    """
    tree = etree.XML(xml)
    schema_tree = etree.XML(SCHEMA_TEMPLATE)
    # Find all unique instances of 'xsi:schemaLocation="<namespace> <path-to-schema.xsd> ..."'
    schema_locations = set(tree.xpath("//*/@xsi:schemaLocation", namespaces={'xsi': XSI}))
    for schema_location in schema_locations:
        # Split namespaces and schema locations ; use strip to remove leading
        # and trailing whitespace.
        namespaces_locations = schema_location.strip().split()
        # Import all found namspace/schema location pairs
        for namespace, location in zip(*[iter(namespaces_locations)] * 2):
            xs_import = etree.Element(XS + "import")
            xs_import.attrib['namespace'] = namespace
            xs_import.attrib['schemaLocation'] = location
            schema_tree.append(xs_import)
    # Contstruct the schema
    schema = etree.XMLSchema(schema_tree)
    # Validate!
    schema.assertValid(tree)

BTW,你的simpletest.xsd缺少targetNamespace。

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.example.org" elementFormDefault="qualified">
    <xs:element name="name" type="xs:string"/>
</xs:schema>

使用上面的代码,您的示例文档将针对此架构进行验证。