代码之家  ›  专栏  ›  技术社区  ›  Eli Courtwright

正则表达式工作正常,但放入XML架构时失败

  •  2
  • Eli Courtwright  · 技术社区  · 16 年前

    我有一个简单的 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 然后尝试执行一个简单的模式验证并报告任何错误:

    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正则表达式没有所有的特性,但是 the documentation I've found 指示我使用的每个功能都应该工作。

    那么,我误解了什么?为什么我的文档会失败?

    2 回复  |  直到 16 年前
        1
  •  3
  •   Michael Mrozek    16 年前

    你的 | 比你想象的要宽。

    (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}
    

    如果你想避免,你需要使用更多的分组;例如。

    ((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}
    
        2
  •  3
  •   Daniel Brückner    16 年前

    表达式有几个错误。

    1. 你允许 00 作为有效月份。
    2. A|BC 比赛 A BC -不 AC 公元前 . 因此,你的表达开始于 (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 我想。