【问题标题】:Regular expression works normally, but fails when placed in an XML schema正则表达式正常工作,但放在 XML 模式中时失败
【发布时间】:2011-02-17 21:10:43
【问题描述】:

我有一个简单的 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 正则表达式并不具备所有功能,但 the documentation I've found 表示我使用的每个功能都应该有效。

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

【问题讨论】:

  • 离题:'{1}'s 有什么原因吗?由于原子只匹配一次,它们看起来是多余的。
  • @outis:是的,它们是多余的,应该删除。他们所做的只是让正则表达式更难阅读,上帝知道正则表达式在这方面不需要任何帮助!

标签: python regex validation schema lxml


【解决方案1】:

表达式有几个错误。

  1. 您允许 00 作为有效月份。
  2. A|BC 匹配 ABC - 不匹配 ACBC。因此,以(0[0-9]{1})| 开头的表达式匹配包含0009 的任何字符串。你想要的是 (0[1-9]|1[0-2])- 只匹配 0112 后跟一个破折号。
  3. 您允许 00 作为有效日期。
  4. 模式未锚定到文本的开头和结尾 - 添加 ^$。这就是您使用 Python 进行测试成功的原因。

顺便说一句 - 你为什么不使用xs:dateTime?它的格式非常相似——我想是yyyy-mm-ddThh:mm:ss.fff

【讨论】:

  • 详细说明第 4 点:Python 正则表达式应该有 添加 锚点来模仿隐式锚定的 XSD 正则表达式的行为。 (另外,接近结尾的. 应该是\.。)但是正如你所说,xs:dateTime 可用,无论如何这可能都是学术性的。
  • 感谢关于xs:dateTime 的观点和建议-事实上,我已经收到了由其他人编写的模式和 xml 文档,我只是想弄清楚如何让它们通过最少的更改,但我肯定会记住 xs:dateTime 类型,以便我下次自己构建架构时使用。
【解决方案2】:

您的|s 匹配范围超出您的想象。

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

【讨论】:

  • 这就是它无法匹配有效输入的原因,但修改后的正则表达式仍然可以匹配很多无效输入,正如@Daniel 指出的那样。
  • 嗯,是的,但那是他的问题 :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-11-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多