自动XSD验证

9
根据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)

我们无法告诉您如何处理您自己的格式。 - Marcin
Marcin,我不理解你的评论。也许我不明白模式验证的工作原理。 - Jono
你是在Windows上做这个吗?据我所知,微软是唯一支持内联模式的公司。 - user849425
在Linux上以及内联执行这个操作对我来说不是很重要。 - Jono
鉴于此,我不确定我是否理解问题。没有官方的方法来提供文档模式。你只能从某个地方获取它。有时它是内联的,但这并不经常被支持。 - Katriel
显示剩余4条评论
2个回答

3
我有一个包含100多个不同架构和XML树的项目。为了管理和验证所有这些架构和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
这并没有回答我的问题,因为您正在定义 XML 文档到模式的显式映射。我的问题是如何推断映射关系。 - Jono
唯一真正推断映射的方法是创建某种类型的映射,但不幸的是,除非在模式定义中可以获取该URL并实际检索XSD文件,或者在每个模式中添加模式位置的注释,这仍然是创建映射而不是推断,否则基本上无法推断。 - Jtello
1
是的,在我上面的示例中,我使用schemaLocation进行引用。但那只是内联引用的一种方式。还有许多其他内联引用的方法(例如-在根节点下方),但我找不到一个可以解析和验证所有这些情况的库。 - Jono

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)

顺便提一下,你的simpletest.xsd缺少目标命名空间。
<?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>

使用上述代码,您的示例文档将符合此模式的验证。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接