否定匹配字符串的XSD限制

时间:2012-03-27 12:05:22

标签: xsd xsd-validation

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

考虑这个规则,它将验证我的字符串是否出现。查找所有Link元素都以此特定字符串开头:/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(否定单个字符) 我知道这可能会对否定一个角色起作用,因为这个问题确实如此:XML schema restriction pattern for not allowing empty strings

该问题中建议的模式<xs:pattern value=".*[^\s].*" />

但在这种情况下,否定只有一个字符不起作用,因为它会正确失败:

  

/site/example.com

但也会错误地失败

  

/溶液

不工作策略2(高级正则表达式预测) 根据这个SO问题(Regular expression to match a line that doesn't contain a word?),你可以用负面预测(?!expr)来解决这个问题。

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

  

^((?!/网站/ example.com)。)* $

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

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

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

2 个答案:

答案 0 :(得分:2)

这在XSD 1.1中更简单,您可以使用断言来确保该值不以您指定的字符串开头。但从概念上讲,即使在XSD 1.0和简单的正则表达式中它也很简单:你想确保字符串不以&#34; /site/example.com&#34;开头。如果确实以这种方式开始,那么你就会对字符串的一系列事实进行逻辑联合:

  • substring(。,1,1)=&#39; /&#39;
  • substring(。,2,1)=&#39; s&#39;
  • substring(。,3,1)=&#39; i&#39;
  • ...
  • 子串(.17,1)=&#39; m&#39;

你想否定这种事实的结合。现在,根据De Morgan定律,〜(a和b和...和z)相当于(~a或~b或......或~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

答案 1 :(得分:1)

你没有提到你是否被绑定到XML Schema 1.0和XPath 1.0,但如果没有,就可以用xs:assert来实现你的目标,这可能需要一些工作 - 这来自存储器...):

<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

干杯,