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

Dan*_*ugg 4 xsd xml-attribute

我是使用XML模式的新手,所以请原谅我的无能,如果这比我自己认为必须的更微不足道.

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

所以有效的元素包括:

<rule methods="get" />
<rule methods="get post" />
<rule methods="post put delete" />
Run Code Online (Sandbox Code Playgroud)

而无效元素包括:

<rule methods="get get" />
<rule methods="foobar post" />
<rule methods="get;post;put" />
Run Code Online (Sandbox Code Playgroud)

我试着用枚举和长度来愚弄,但我不相信我理解我需要做什么(或者如果它实际上是可能的话,尽管看起来好像应该这样)


这就是我现在所处的位置,感谢@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>
Run Code Online (Sandbox Code Playgroud)

哪个有效,除了重复(get getpost post post)和缺少空格(getpostpostputdelete)


编辑:

在玩了一下之后,我提出了一个想法:列举所有可能的序列.值得庆幸的是,这份名单是(暂时)固定在四个通常的运输方式,get,post,put,和delete,所以我想通:

<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>
Run Code Online (Sandbox Code Playgroud)

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

DRH*_*DRH 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>
Run Code Online (Sandbox Code Playgroud)

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


Dan*_*ugg 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)
)
$
Run Code Online (Sandbox Code Playgroud)

与 XML 兼容:

((get(\spost)?(\sput)?(\sdelete)?(\shead)?(\soptions)?)|(post(\sput)?(\sdelete)?(\shead)?(\soptions)?)|(put(\sdelete)?(\shead)?(\soptions)?)|(delete(\shead)?(\soptions)?)|(head(\soptions)?)|(options))
Run Code Online (Sandbox Code Playgroud)

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

无论如何,总结一下:

"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
Run Code Online (Sandbox Code Playgroud)

这种模式的规模并不是最大的,因为每个新的“令牌”都需要包含在每个组中,但考虑到问题域是 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));
Run Code Online (Sandbox Code Playgroud)

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