【问题标题】:XSD restriction that negates a matching string否定匹配字符串的 XSD 限制
【发布时间】:2012-03-27 12:05:22
【问题描述】:

我希望我的 XSD 验证字符串的内容。具体来说,我想验证某个字符串不会出现

考虑这条规则,它将验证我的字符串是否出现。查找所有 Linkelements 以这个特定的字符串开头:/site/example.com

<xs:element name="Link" type="xs:normalizedString" minOccurs="0">
  <xs:simpleType>
    <xs:restriction base="xs:token">
      <xs:pattern value="(/site/example\.com).*"/>
    </xs:restriction>
  </xs:simpleType>
</xs:element>                 

换句话说,上面的表达式验证所有Link 元素都以/site/example.com 开头。您如何反转上面的表达式,以便**验证没有Link 元素以/site/example.com 开头?

我尝试了以下正则表达式,但没有成功:/[^(site/example\.com)].*,所以这不起作用:

无效的策略1(单个字符的否定) 我知道这可能适用于否定单个字符,因为这个 SO 问题就是这样做的:XML schema restriction pattern for not allowing empty strings

该问题中的建议模式&lt;xs:pattern value=".*[^\s].*" /&gt;

但在这种情况下,仅否定单个字符是行不通的,因为它会正确地失败:

/site/example.com

但它也会错误地失败

/解决方案

不起作用的策略 2(高级正则表达式前瞻) 根据这个 SO 问题 (Regular expression to match a line that doesn't contain a word?),您可以通过否定前瞻 (?!expr) 来解决这个问题。

所以这将在普通的正则表达式中工作:

^((?!/site/example.com).)*$

现在,不幸的是 xsd 验证仅支持有限的正则表达式。根据这个网站,不支持前瞻:regular-expressions.info -- xsd

这几乎描述了我到目前为止所尝试的内容。

我的问题是,我如何否定 XSD 模式中的正则表达式?

【问题讨论】:

    标签: xsd xsd-validation


    【解决方案1】:

    这在 XSD 1.1 中更简单,您可以使用断言来确保值不以您指定的字符串开头。但从概念上讲,即使在 XSD 1.0 和简单的正则表达式中也足够简单:您要确保字符串不以“/site/example.com”开头。如果它确实以这种方式开始,那么您将获得关于字符串的一系列事实的逻辑连接:

    • 子字符串(., 1, 1) = '/'
    • substring(., 2, 1) = 's'
    • substring(., 3, 1) = 'i'
    • ...
    • substring(.17, 1) = 'm'

    你想否定这些事实的结合。现在,根据德摩根定律,~(a and b and ... and z) 等价于 (~a or ~b or ... or ~z)。因此,您可以通过编写以下术语的析取来做您需要的事情:

        [^/].*
        |.([^s].*)?
        |.{2}([^i].*)?
        |.{3}([^t].*)?
        |.{4}([^e].*)?
        |.{5}([^/].*)?
        |.{6}([^e].*)?
        |.{7}([^x].*)?
        |.{8}([^a].*)?
        |.{9}([^m].*)?
        |.{10}([^p].*)?
        |.{11}([^l].*)?
        |.{12}([^e].*)?
        |.{13}([^\.].*)?
        |.{14}([^c].*)?
        |.{15}([^o].*)?
        |.{16}([^m].*)?
    

    在上面的每个术语中,[^s].* 形式的子表达式被包裹在(...)? 中——术语.{2}([^i].*)? 表示如果第三个字符不是i 或者如果根本没有第三个字符。这样可以确保不排除长度小于 17 个字符的字符串,即使它们恰好是禁止字符串的前缀。

    当然,要在 XSD 架构文档中使用它,您需要删除所有空格,这会使正则表达式更难阅读。

    [添加,2016 年 6 月] 另见 this related and more general question

    【讨论】:

      【解决方案2】:

      您没有提到您是否绑定到 XML Schema 1.0 和 XPath 1.0,但如果不是,则可以使用 xs:assert's 来实现您的目标,沿着这个思路(可能需要一些工作 - 这是来自记忆...):

      <xs:element name="Link" type="xs:normalizedString" minOccurs="0">
        <xs:simpleType>
          <xs:restriction base="xs:token">
            <xs:assert test="not( fn:starts-with( $value , '/site/example.com' ) )" />
          </xs:restriction>
        </xs:simpleType>
      </xs:element>  
      

      一些可能感兴趣的链接:

      http://www.ibm.com/developerworks/library/x-xml11pt2/

      http://www.w3.org/TR/xpath-functions/#func-starts-with

      干杯,

      【讨论】:

      • 非常感谢,我会调查一下
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-07-20
      • 1970-01-01
      • 1970-01-01
      • 2018-05-01
      • 1970-01-01
      • 2019-08-01
      相关资源
      最近更新 更多