一个XML模式如何要求元素按属性排序?

5
假设我有一个长这样的XML文件:
<Transactions>
<Transaction OrderID="5"> ... </Transaction>
<Transaction OrderID="6"> ... </Transaction>
<Transaction OrderID="11"> ... </Transaction>
<Transaction OrderID="7"> ... </Transaction>
</Transactions>

使用XML schema,可以指示订单#11不在正确的顺序中吗? 每个Transaction元素单独通过验证,但OrderID应按递增顺序排列。
另一个相关的问题:验证规则是否可以指示数字是否可以被跳过? 例如,没有交易#8、9或10。
1个回答

1
如果您的验证器支持XSD 1.1,您可以使用xs:assert来拒绝特定的属性值,如下所示:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" 
           xmlns:vc="http://www.w3.org/2007/XMLSchema-versioning" 
           elementFormDefault="qualified" 
           attributeFormDefault="unqualified"
           vc:minVersion="1.1">
   <xs:element name="Transactions">
      <xs:complexType>
         <xs:sequence>
            <xs:element name="Transaction" maxOccurs="unbounded">
               <xs:complexType mixed="true">
                   <xs:attribute name="OrderID" type="xs:integer"/>
                   <xs:assert test="empty(index-of((8,9,10),@OrderID))"/>
               </xs:complexType>                                
            </xs:element>
         </xs:sequence>
      </xs:complexType>
   </xs:element>
</xs:schema>

这应该能回答你的第二个问题。
至于你的第一个问题,我认为无法进行订单验证。但是,您可以使用XSLT对XML文档进行排序。
----- 添加了对第一个问题的答案 -----
谢谢,Michael Kay。好的...这是您第一个问题的答案。
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xs:element name="Transactions">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="Transaction" maxOccurs="unbounded">
                    <xs:complexType mixed="true">
                        <xs:attribute name="OrderID" type="xs:integer"/>
                        <xs:assert test="empty(index-of((8,9,10),@OrderID))"/>
                    </xs:complexType>
                </xs:element>
            </xs:sequence>
            <xs:assert test="every $x in Transaction satisfies 
                             (empty($x/preceding-sibling::*) or 
                             ($x/@OrderID gt $x/preceding-sibling::*[1]/@OrderID))"/>
        </xs:complexType>
    </xs:element>
</xs:schema>

2
是的,可以进行订单验证。例如 <xs:assert test="every $x in * satisfies not($x/@att gt $x/preceding-sibling::*[1]/@att)"/> - Michael Kay
感谢Chong Lip Phang。老实说,我不太理解你的答案是否能解决我的问题。当你写 <xs:assert test="empty(index-of((8,9,10),@OrderID))"/> 时,8、9、10是否指的是OrderID的特定值?我正在处理的文件中有大约30K个交易。任何对我有效的方法都需要在没有OrderID特定值的情况下工作。第二个<xs:assert test...看起来像是通用答案。这两个都需要吗? - Selecter
是的,如果OrderID的值为8、9或10,则<xs:assert test="empty(index-of((8,9,10),@OrderID))"/>会导致验证失败。如果XML数据很多,那么您可能需要一个规则来匹配特定的模式。如果您省略此断言规则并且OrderID跳过8、9或10,则验证仍将通过。 - Chong Lip Phang
第二个xs:assert...如果OrderID的值不是按升序排列,则会导致验证失败。因此,这里实际上有两个断言。您可以省略两个,使用一个或使用两个。这取决于您希望验证什么。 - Chong Lip Phang

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接