【问题标题】:XML schema; multiple from a list of valid attribute valuesXML 模式;来自有效属性值列表的多个
【发布时间】:2011-12-31 15:14:35
【问题描述】:

我对使用 XML 模式相当陌生,所以如果这比我自己认为的更琐碎,请原谅我的无能。

我正在尝试创建一个必需属性,该属性必须包含列表中的 1 个或多个空格分隔的字符串值。该列表是 4 种典型的 HTTP 请求方法; getpostputdelete

所以有效的元素包括:

<rule methods="get" />
<rule methods="get post" />
<rule methods="post put delete" />

而无效元素包括:

<rule methods="get get" />
<rule methods="foobar post" />
<rule methods="get;post;put" />

我试过用枚举和长度来愚弄,但我不相信我理解我需要做什么(或者就此而言,如果它实际上是可能的,尽管它似乎应该是


感谢@tdrury,这就是我现在所处的位置:

<xs:attribute name="methods" use="required">
    <xs:simpleType>
        <xs:restriction base="xs:string">
            <xs:whiteSpace value="collapse" />
            <xs:pattern value="(?:(?:get|post|put|delete)\s?){1,4}" />
        </xs:restriction>
    </xs:simpleType>
</xs:attribute>

除了重复(get getpost post post)和不存在空格(getpostpostputdelete)之外,这有效。 p>


编辑

在玩了一会儿之后,我想出了一个主意:枚举所有可能的序列。值得庆幸的是,这个列表(暂时)固定为四种常用的传输方式,getpostputdelete,所以我想:

<xs:restriction base="xs:string">
    <xs:whiteSpace value="collapse" />
    <xs:enumeration value="delete" />
    <xs:enumeration value="put" />
    <xs:enumeration value="put delete" />
    <xs:enumeration value="post" />
    <xs:enumeration value="post delete" />
    <xs:enumeration value="post put" />
    <xs:enumeration value="post put delete" />
    <xs:enumeration value="get" />
    <xs:enumeration value="get delete" />
    <xs:enumeration value="get put" />
    <xs:enumeration value="get put delete" />
    <xs:enumeration value="get post" />
    <xs:enumeration value="get post delete" />
    <xs:enumeration value="get post put" />
    <xs:enumeration value="get post put delete" />
</xs:restriction>

谁能看出这不是是个好主意的原因?

【问题讨论】:

    标签: xsd xml-attribute


    【解决方案1】:

    基本问题也可以通过枚举来解决:

    <xs:attribute name="methods" use="required">
        <xs:simpleType>
            <xs:restriction>
                <xs:simpleType>
                    <xs:list>
                        <xs:simpleType>
                            <xs:restriction base="xs:token">
                                <xs:enumeration value="get"/>
                                <xs:enumeration value="post"/>
                                <xs:enumeration value="put"/>
                                <xs:enumeration value="delete"/>
                            </xs:restriction>
                        </xs:simpleType>
                    </xs:list>
                </xs:simpleType>
                <xs:minLength value="1"/>
            </xs:restriction>
        </xs:simpleType>
    </xs:attribute>
    

    不幸的是,这与&lt;xs:pattern&gt; 解决方案具有相同的限制,并且无法验证列表中的每个令牌都是唯一的。然而,它确实解决了空白问题(getpost 将被拒绝)。

    【讨论】:

      【解决方案2】:

      您可以使用正则表达式作为对 simpleType 的限制:http://www.w3.org/TR/xmlschema-2/#dt-pattern

      我不是正则表达式专家,但应该是这样的:

      <xs:attribute name="methods" use="required">
         <xs:simpleType>
            <xs:restriction base="xs:string">
               <xs:pattern value='((get|post|put|delete)[/s]*){4}'/>
            </xs:restriction>
         </xs:simpleType>
      </xs:attribute>
      

      【讨论】:

      • 谢谢@tdrury -- 那很接近了,我将它修改为(?:(?:get|post|put|delete)\s?){1,4} 可以工作,除了get getgetpost 等。似乎没有办法对重复项无效。
      【解决方案3】:

      在定期搞砸这个之后,我想出了这个庞大的模式;在 PCRE 漂亮打印中的第一名:

      ^
      (
        (get     (\s post)?    (\s put)?     (\s delete)?  (\s head)?    (\s options)?)
      | (post    (\s put)?     (\s delete)?  (\s head)?    (\s options)?)
      | (put     (\s delete)?  (\s head)?    (\s options)?)
      | (delete  (\s head)?    (\s options)?)
      | (head    (\s options)?)
      | (options)
      )
      $
      

      与 XML 兼容:

      ((get(\spost)?(\sput)?(\sdelete)?(\shead)?(\soptions)?)|(post(\sput)?(\sdelete)?(\shead)?(\soptions)?)|(put(\sdelete)?(\shead)?(\soptions)?)|(delete(\shead)?(\soptions)?)|(head(\soptions)?)|(options))
      

      这将成功匹配 get post put delete headoptions 的任何排列,进一步要求它们正确排序(这也很好 )

      总之,总结一下:

      "get post put delete head options" // match
      
      "get put delete options"           // match
      
      "get get post put"                 // fail; double get
      
      "get foo post put"                 // fail; invalid token, foo
      
      "post delete"                      // match
      
      "options get"                      // fail; ordering
      

      这种模式的规模不是最大的,因为每个新的“令牌”都需要包含在每个组中,但考虑到问题域是 HTTP 方法,更改是不可预见的,我认为它应该可以正常工作。


      另外,这里有一个生成模式的快速脚本 (PHP):

      $tokens = ['get', 'post', 'put', 'delete', 'head', 'options'];
      
      echo implode('|', array_map(function ($token) use (&$tokens) {
          return sprintf('(%s%s)', array_shift($tokens),
              implode(null, array_map(function ($token) {
                  return sprintf('(\s%s)?', $token);
              }, $tokens)));
      }, $tokens));
      

      它省略了最外面的(),因为我认为没有必要。

      【讨论】:

        【解决方案4】:

        你可以像这样处理空格:

        (get|post|put|delete)(\sget|\spost|\sput|\sdelete){0,3}

        它不会匹配 getpost。

        【讨论】:

          【解决方案5】:

          我需要与您想要的类似的东西,但我不希望强制执行任何命令,并且我不希望模式随着更多可能值的添加而呈指数级增长。

          以你的枚举为例,我想出的模式是这样的:

          (?:get|post|put|delete|head|options)(?:\s(?:(?<!.*\bget\b.*)get|
          (?<!.*\bpost\b.*)post|(?<!.*\bput\b.*)put|(?<!.*\bdelete\b.*)delete|
          (?<!.*\bhead\b.*)head|(?<!.*\boptions\b.*)options))*
          

          这部分

          (?:[values])
          

          只要求至少选择一个选项。如果也不允许任何值,请将整个表达式括起来:(?:[...])?

          剩下的

          (?:\s(?:[values-with-restraints]))*
          

          允许零个或多个空格加值组合。值以这种格式给出

          (?<!.*\b[value]\b.*)[value]
          

          它使用否定的后视(?&lt;![...]) 来确保它以前不存在于文本中。我正在使用单词边界标记\b 来确保属于其他选项的选项不会引起问题。例如,如果您有选项 foobarfoobar,您不希望选项 foobar 阻止 foobar 选项合法。

          请记住,由于这将进入 XML,因此当您将其放入架构时,您必须将 &amp;lt; 字符替换为 &amp;lt;

          另外,最后警告,并非所有正则表达式处理器都支持lookbehind 功能。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2017-08-31
            • 1970-01-01
            • 2013-01-22
            相关资源
            最近更新 更多