2016-12-21 12 views
1

Можно использовать lxml для проверки XML-файлов по данной схеме XSD.Как проверить схему XSD с помощью lxml, но игнорировать элементы, которые соответствуют заданному шаблону?

Есть ли способ применить эту проверку в менее строгом смысле, игнорируя все элементы, содержащие специальные выражения?

Рассмотрим следующий пример: Скажем, у меня есть xml_file:

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

Теперь я запустить программу на этом файле, который заменяя {{...}} -expressions и производит новый файл:

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, однако, как моя программа делает некоторые другие дорогостоящие задачи, я хотел бы сделать именно это, игнорируя при этом все строки, содержащие любые {{...}} -expressions:

<foo>99</foo>  <!-- should be checked--> 
<foo>{{var1}}</foo> <!-- should be ignored --> 
<foo>{{var2}}</foo> <!-- should be ignored --> 
<foo>999</foo>  <!-- should be checked--> 

EDIT: Возможный подход решение: Одна из идей было бы определить две схемы

  • строгая вторая схема для нового файла, что позволяет только целые числа
  • расслабленные схемы для старого файла, позволяя как целые и произвольные строки с {{..}} -expressions

Однако, чтобы избежать избыточной задачи сохранения два схем синхронизации один будет нужен способ для создания расслабленного от строгая схема автоматически. Это звучит довольно многообещающе, так как обе схемы имеют одинаковую структуру , только отличающиеся ограничениями на содержание некоторых элементов. Есть ли простая концепция, предлагаемая XSD, которая позволяет просто «наследовать» из одной схемы, а затем «присоединять» дополнительные релаксации к отдельным элементам?

+0

Я не думаю, что это возможно без изменения XML или схемы. Поскольку вы не можете изменить XML, вы можете изменить схему? Потому что вы можете определить тип объединения для '', что позволяет * либо * целые числа, либо * '{{var ...}}'. – Meyer

+0

Спасибо, я уже ему так. Тем не менее, я все еще хочу использовать строгую целую проверку * после * замен и запрещать '{{...}}' -выражения. Первая проверка - это только предварительное обнаружение проблем для экономии времени, вторая проверка. Чтобы убедиться, что '{{var1}}' заменено целым числом в новом файле, также необходимо исключить случаи, когда '{{var1}}' заменяется на '{{var3}}' в * новом * файле , Здесь, используя ту же схему для обеих проверок, будет дано ложное положительное значение. – flonk

+0

С другой стороны, я боюсь, что использование двух схем (смягченного первого и более строгого второго) приводит к избыточности, особенно потому, что мне нужно очень часто менять и обновлять схему. – flonk

ответ

1

Чтобы ответить на отредактированный вопрос, можно составить схемы с помощью механизма (и 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> 

расслаблен схемы для проверки перед заменой. Она включает в себя compontents от общей схемы, и определяет непринужденную 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. Но они имеют более сложную семантику и лично, я стараюсь их избегать.

+0

Спасибо за ваш пример. Я думаю, что он еще не решил избыточность, поскольку строгое ограничение '' на '' должно происходить только один раз *. Может ли ваше решение улучшить в этом смысле? Я думаю о чем-то вроде «прикрепления» релаксаций к строгой схеме. Я совершенно незнаком с XSD, но с точки зрения наследования я бы предпочел * вывести '' relaxed' из 'strict', а не выводить как из абстрактной базы' common'. – flonk

+0

Что мне нравится в вашем ответе, так это то, что он уже обеспечивает четкое разделение ограничений структуры и содержимого. – flonk

+0

@flonk, проблема в том, что [простые типы] (http://www.w3.org/TR/xmlschema-1/#declare-datatype) могут быть ограничены, а не расширены. Таким образом, вы не можете перейти от строгого к расслабленному. – Meyer

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 и вставлять его в строгую версию схемы. Но это будет намного сложнее.

 Смежные вопросы

  • Нет связанных вопросов^_^