XML模式;有效属性值列表中的多个

时间:2011-12-31 15:14:35

标签: xsd xml-attribute

对于使用XML模式我是个新手,所以请原谅我的无能,如果这比我自己认为必须的那么简单。

我正在尝试创建一个必需的属性,该属性必须包含一个或多个列表中以空格分隔的字符串值。该列表是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 )和缺少空格(,例如getpost或{{1} }


修改

在玩了一下之后,我提出了一个想法:列举所有可能的序列。值得庆幸的是,此列表(暂时)已修复为四种常用传输方法postputdeletegetpostput ,所以我想:

delete

任何人都可以看到这个是个好主意的原因吗?

5 个答案:

答案 0 :(得分:10)

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

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

遗憾的是,这与<xs:pattern>解决方案具有相同的限制,无法验证列表中的每个标记是否唯一。然而,它确实解决了空白问题(getpost将被拒绝)。

答案 1 :(得分:3)

您可以使用正则表达式作为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>

答案 2 :(得分: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));

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

答案 3 :(得分:1)

你可以处理这样的空格:

(获取|发表|把|删除)(\ sget操作| \ spost | \ sput | \ sdelete){0,3}

它与getpost不匹配。

答案 4 :(得分:0)

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

以您的枚举为例,我提出的模式如下:

(?: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]

使用负面后瞻(?<![...])来确保它以前在文本中不存在。我使用字边界标记\b来确保其他选项不会导致问题。例如,如果您有选项foobarfoobar,则您不希望选项foobar阻止foo和{{ 1}}合法的选择。

请记住,由于这是针对XML的,因此当您将bar字符放入模式时,必须将<字符替换为&lt;

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