2012-03-23 19 views
7

lxmlのドキュメントによると、 "DTDは解析されたドキュメントのDOCTYPEに基づいて自動的に取得されるため、DTD検証が有効になっているパーサーを使用するだけです。自動XSD検証

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) 
+0

独自のフォーマットをどのように処理するかはわかりません。 – Marcin

+0

Marcin、私はあなたのコメントを理解していません。おそらく、私はスキーマ検証の仕組みを理解していないでしょう。 – Jono

+0

Windowsでこれをやっていますか? AFAIK Microsoftは、インラインスキーマをサポートする唯一の企業です。 –

答えて

3

私は終わっていたプロジェクトを持っています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ヘルパー関数を持っていたファイルにこの関数を配置しました。

+0

XML文書のスキーマへの明示的なマッピングを定義しているので、これは私の質問には答えません。私の質問のポイントは、マッピングを推測する方法です。 – Jono

+0

マッピングを実際に推測する唯一の方法は、残念なことにある種のマッピングを作成することです。スキーマの定義で、そのURLを取得して実際にxsdファイルを取得できない限り、またはスキーマの場所のコメントを追加することはできますが、まだマッピングを作成して推測していないので、基本的にはできません。 – Jtello

+0

上記のサンプルでは、​​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で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> 

上記のコードでは、サンプルドキュメントはこのスキーマに対して検証されます。