Регулярное выражение работает нормально, но завершается неудачно, когда помещается в схему XML - PullRequest
2 голосов
/ 11 мая 2010

У меня есть простой doc.xml файл, который содержит один корневой элемент с атрибутом Timestamp:

<?xml version="1.0" encoding="utf-8"?>
<root Timestamp="04-21-2010 16:00:19.000" />

Я бы хотел проверить этот документ по моей простой schema.xsd, чтобы убедиться, что метка времени имеет правильный формат:

<?xml version="1.0" encoding="utf-8"?>
<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:element name="root">
    <xs:complexType>
      <xs:attribute name="Timestamp" use="required" type="timeStampType"/>
    </xs:complexType>
  </xs:element>
  <xs:simpleType name="timeStampType">
    <xs:restriction base="xs:string">
      <xs:pattern value="(0[0-9]{1})|(1[0-2]{1})-(3[0-1]{1}|[0-2]{1}[0-9]{1})-[2-9]{1}[0-9]{3} ([0-1]{1}[0-9]{1}|2[0-3]{1}):[0-5]{1}[0-9]{1}:[0-5]{1}[0-9]{1}.[0-9]{3}" />
    </xs:restriction>
  </xs:simpleType>
</xs:schema>

Поэтому я использую модуль lxml Python и пытаюсь выполнить простую проверку схемы и сообщить о любых ошибках:

from lxml import etree

schema = etree.XMLSchema( etree.parse("schema.xsd") )
doc = etree.parse("doc.xml")

if not schema.validate(doc):
    for e in schema.error_log:
        print e.message

Мой документ XML не проходит проверку со следующими сообщениями об ошибках:

Element 'root', attribute 'Timestamp': [facet 'pattern'] The value '04-21-2010 16:00:19.000' is not accepted by the pattern '(0[0-9]{1})|(1[0-2]{1})-(3[0-1]{1}|[0-2]{1}[0-9]{1})-[2-9]{1}[0-9]{3} ([0-1]{1}[0-9]{1}|2[0-3]{1}):[0-5]{1}[0-9]{1}:[0-5]{1}[0-9]{1}.[0-9]{3}'.
Element 'root', attribute 'Timestamp': '04-21-2010 16:00:19.000' is not a valid value of the atomic type 'timeStampType'.

Так что, похоже, мое регулярное выражение должно быть ошибочным. Но когда я пытаюсь проверить регулярное выражение в командной строке, оно передает:

>>> import re
>>> pat = '(0[0-9]{1})|(1[0-2]{1})-(3[0-1]{1}|[0-2]{1}[0-9]{1})-[2-9]{1}[0-9]{3} ([0-1]{1}[0-9]{1}|2[0-3]{1}):[0-5]{1}[0-9]{1}:[0-5]{1}[0-9]{1}.[0-9]{3}'
>>> assert re.match(pat, '04-21-2010 16:00:19.000')
>>> 

Я знаю, что регулярные выражения XSD не имеют всех функций, но документация, которую я нашел , указывает, что каждая функция, которую я использую, должна работать.

Так что же я неправильно понимаю и почему мой документ не работает?

Ответы [ 2 ]

3 голосов
/ 11 мая 2010

В выражении есть несколько ошибок.

  1. Вы разрешаете 00 как действительный месяц.
  2. A|BC соответствует A и BC - не AC и BC. Следовательно, ваше выражение, начинающееся с (0[0-9]{1})|, соответствует любой строке, содержащей от 00 до 09. (0[1-9]|1[0-2])- соответствует только 01 - 12, за которым следует тире.
  3. Вы разрешаете 00 как действительный день.
  4. Шаблон не привязан к началу и концу текста - добавьте ^ и $. Вот почему ваш тест с использованием Python прошел успешно.

Кстати - а почему бы вам не использовать xs:dateTime? У него очень похожий формат - yyyy-mm-ddThh:mm:ss.fff Я думаю.

3 голосов
/ 11 мая 2010

Ваши | с совпадают шире, чем вы думаете.

(0[0-9]{1})|(1[0-2]{1})-(3[0-1]{1}|[0-2]{1}[0-9]{1})-[2-9]{1}[0-9]{3}

анализируется как:

(0[0-9]{1})
    -or-
(1[0-2]{1})-(3[0-1]{1}|[0-2]{1}[0-9]{1})-[2-9]{1}[0-9]{3}

Вам нужно использовать больше группировок, если вы хотите избежать этого; например, * +1008 *

((0[0-9]{1})|(1[0-2]{1}))-((3[0-1]{1}|[0-2]{1}[0-9]{1}))-[2-9]{1}[0-9]{3} (([0-1]{1}[0-9]{1}|2[0-3]{1})):[0-5]{1}[0-9]{1}:[0-5]{1}[0-9]{1}.[0-9]{3}
...