对于使用XML模式我是个新手,所以请原谅我的无能,如果这比我自己认为必须的那么简单。
我正在尝试创建一个必需的属性,该属性必须包含一个或多个列表中以空格分隔的字符串值。该列表是4种典型的HTTP请求方法; get
,post
,put
和delete
。
所以有效的元素包括:
<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 get
或post post post
)和缺少空格(,例如getpost
或{{1} } )
修改:
在玩了一下之后,我提出了一个想法:列举所有可能的序列。值得庆幸的是,此列表(暂时)已修复为四种常用传输方法postputdelete
,get
,post
和put
,所以我想:
delete
任何人都可以看到这个不是个好主意的原因吗?
答案 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
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
这种模式不能扩展到最大,因为每个新的“令牌”都需要包含在每个组中,但鉴于问题域是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
来确保其他选项不会导致问题。例如,如果您有选项foo
,bar
和foobar
,则您不希望选项foobar
阻止foo
和{{ 1}}合法的选择。
请记住,由于这是针对XML的,因此当您将bar
字符放入模式时,必须将<
字符替换为<
。
此外,最后警告,并非所有正则表达式处理器都支持lookbehind功能。