xsd模式中的XPath断言



我有以下xsd模式

<?xml version="1.1" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace = "http://www.ludd21.com/kPartModel"
xmlns = "http://www.ludd21.com/kPartModel"
elementFormDefault="qualified"
>   
<xs:element name="kPartModel">
<xs:complexType>
<xs:sequence>
<xs:element ref="kPartsPiece"  minOccurs="1" maxOccurs = "unbounded"/>
</xs:sequence>
<xs:attribute name="modelName" type="xs:NCName" use = "required"/>
</xs:complexType>
<!--piecename must be unique within kpModel-->
<xs:unique name= "kPartModel">
<xs:selector xpath="*"/>
<xs:field xpath= "@pieceName"/>
</xs:unique>
</xs:element>

<xs:element name="kPartsPiece">
<xs:complexType>
<xs:sequence>
<xs:element ref= "kPartsList"/>
</xs:sequence>         
<xs:attribute name="pieceName" type="xs:NCName"/>
<!-- if they exist previousnum and nextsnum must contain valid partNumber that is referring to a part in kpartsList-->
<xs:assert test = "every $x in kPartsList/@previousnums satisfies exists(kPartsList/@partNumber)"/>
<xs:assert test = "every $x in kPartsList/@nextsnums satisfies exists (kPartsList/@partNumber)"/>
</xs:complexType>
<!-- @partNumber is unique across kPartsList -->
<xs:unique name= "kPartsList">
<xs:selector xpath="*"/>
<xs:field xpath= "@partNumber"/>
</xs:unique>
</xs:element>

<xs:element name = "kPartsList" >
<xs:complexType>
<xs:sequence>
<xs:choice >
<xs:element ref = "castOnPartSeg"/>
<xs:element ref = "castOnPartPoint"/>
</xs:choice>
<xs:choice  minOccurs= "0" maxOccurs = "unbounded">
<xs:element ref = "castOnPartSeg" />
<xs:element ref = "castOnPartPoint" />
<xs:element ref = "castOffPartSeg" />
<xs:element ref = "castOffPartPoint"/>
<xs:element ref = "joinPart"/>
<xs:element ref = "splitPart" />
<xs:element ref = "segSplitPart"/>  
</xs:choice>
</xs:sequence>        
</xs:complexType>      
</xs:element>


<xs:element name="castOnPartPoint">
<xs:complexType>
<xs:attribute name ="nextsnum" type = "kpRefsList" use = "required"/>
<xs:attribute name = "partNumber" type = "xs:nonNegativeInteger" use = "required"/>
<xs:attribute name = "heightd" type = "decimal5digits" use = "required"/>
</xs:complexType>
</xs:element>

<xs:element name="castOnPartSeg">
<xs:complexType>
<xs:attribute name = "nextsnum"  type = "kpRefsList" use = "required"/>
<xs:attribute name = "partNumber" type = "xs:nonNegativeInteger" use = "required"/>
<xs:attribute name = "heightd" type = "decimal5digits" use = "required"/>
</xs:complexType>
</xs:element>

<xs:element name="castOffPartPoint">
<xs:complexType>
<xs:attribute name ="previousnum" type = "kpRefsList" use = "required"/> 
<xs:attribute name = "partNumber" type = "xs:nonNegativeInteger" use = "required"/>
<xs:attribute name = "heightd" type = "decimal5digits" fixed = "0" use = "required"/>
</xs:complexType>
</xs:element>


<xs:element name="castOffPartSeg">
<xs:complexType>
<xs:attribute name ="previousnum" type = "kpRefsList" use = "required"/> 
<xs:attribute name = "partNumber" type = "xs:nonNegativeInteger" use = "required"/>
<xs:attribute name = "heightd" type = "decimal5digits" fixed="0" use = "required"/>
</xs:complexType> 
</xs:element>

<xs:element name="splitPart">
<xs:complexType>
<xs:attribute name ="previousnum" type = "kpRefsList" use = "required"/> 
<xs:attribute name ="nextsnum" type = "kpRefsList" use = "required"/>
<xs:attribute name = "partNumber" type = "xs:nonNegativeInteger" use = "required"/>
<xs:attribute name = "heightd" type = "decimal5digits" use = "required"/>
</xs:complexType>
</xs:element>

<xs:element name="segSplitPart">
<xs:complexType>
<xs:attribute name ="previousnum"  type = "kpRefsList" use = "required"/>        
<xs:attribute name = "partNumber" type = "xs:nonNegativeInteger" use = "required"/>
<xs:attribute name = "heightd" type = "decimal5digits" fixed= "0" use = "required"/>       
</xs:complexType>
</xs:element>

<xs:element name="joinPart">
<xs:complexType>
<xs:attribute name ="nextsnum"  type = "kpRefsList" use = "required"/>   
<xs:attribute name ="previousnum" type = "kpRefsListmin2" use = "required"/>
<xs:attribute name = "partNumber" type = "xs:nonNegativeInteger" use = "required"/>
<xs:attribute name = "heightd" type = "decimal5digits" use = "required"/>      
</xs:complexType>
</xs:element>
<xs:simpleType name = "kpRefsList">
<xs:list itemType= "xs:nonNegativeInteger"/>
</xs:simpleType>

<xs:simpleType name="kpRefsListmin2"> 
<xs:restriction base = "kpRefsList"> 
<xs:minLength value = "2"/>
</xs:restriction>
</xs:simpleType>


<xs:simpleType name ="decimal5digits">
<xs:restriction base = "xs:decimal">
<xs:fractionDigits value="5"/>
</xs:restriction>
</xs:simpleType>    
</xs:schema>

包含第28行和29行不正确的断言。我尝试过几种解决方案,但作为XPath的新手,我没有成功。目标是测试previousnum中的每个数字(nextnum也一样)是否是kPartsPiece的kPartsList中某个部件的有效partNumber。

下面是一个xml片段,应该根据模式进行验证;

<ns0:kPartModel xmlns:ns0="http://www.ludd21.com/kPartModel" modelName="manysingulars">
<ns0:kPartsPiece pieceName="manysingulars">
<ns0:kPartsList>
<ns0:castOnPartSeg nextsnum="1" partNumber="0" heightd="11.82912" />
<ns0:joinPart nextsnum="3" previousnum="0 2" partNumber="1" heightd="8.08932" />
<ns0:castOnPartPoint nextsnum="1" partNumber="2" heightd="3.80881" />
<ns0:joinPart nextsnum="6" previousnum="1 5 4" partNumber="3" heightd="8.65979" />
<ns0:castOnPartSeg nextsnum="3" partNumber="4" heightd="16.36741" />
<ns0:castOnPartSeg nextsnum="3" partNumber="5" heightd="6.48911" />
<ns0:joinPart nextsnum="8 9 10" previousnum="3 7" partNumber="6" heightd="5.23755" />
<ns0:castOnPartPoint nextsnum="6" partNumber="7" heightd="18.12524" />
<ns0:splitPart previousnum="6" nextsnum="12" partNumber="8" heightd="8.63775" />
<ns0:splitPart previousnum="6" nextsnum="11" partNumber="9" heightd="8.63775" />
<ns0:segSplitPart previousnum="6" partNumber="10" heightd="0.00000" />
<ns0:castOffPartSeg previousnum="9" partNumber="11" heightd="0.00000" />
<ns0:castOffPartSeg previousnum="8" partNumber="12" heightd="0.00000" />
</ns0:kPartsList>
</ns0:kPartsPiece>

& lt;/ns0: kPartModel>

下面是一个稍微简化但与您的需求相似的示例,具有列表类型和断言:

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"
xmlns:vc="http://www.w3.org/2007/XMLSchema-versioning" vc:minVersion="1.1">
<xs:element name="root">
<xs:complexType>
<xs:sequence>
<xs:element ref="parts"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="parts">
<xs:complexType>
<xs:sequence>
<xs:element maxOccurs="unbounded" ref="part"/>
</xs:sequence>
<xs:assert id="test-reference-id" test="every $part in part satisfies every $id in $part/data(@next) satisfies some $part2 in part satisfies $id = $part2/@id"/>
</xs:complexType>
</xs:element>
<xs:element name="part">
<xs:complexType>
<xs:attribute name="id" use="required" type="xs:string"/>
<xs:attribute name="next" type="id-list"/>
</xs:complexType>
</xs:element>
<xs:simpleType name="id-list">
<xs:list itemType="xs:string"></xs:list>
</xs:simpleType>
</xs:schema>

的例子
<root>
<parts>
<part id="p1" next="p2 p4"/>
<part id="p2" next="p3 p4 p5"/>
<part id="p3" next="p4"/>
<part id="p4"/>
</parts>
</root>

则断言失败,而

<root>
<parts>
<part id="p1" next="p2 p4"/>
<part id="p2" next="p3 p4"/>
<part id="p3" next="p4"/>
<part id="p4"/>
</parts>
</root>

是有效的。

我试图实现你的断言是

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace = "http://www.ludd21.com/kPartModel"
xmlns = "http://www.ludd21.com/kPartModel"
elementFormDefault="qualified" 
vc:minVersion = "1.1"
xpathDefaultNamespace="##targetNamespace"
xmlns:vc="http://www.w3.org/2007/XMLSchema-versioning"
>   
<xs:element name="kPartModel">
<xs:complexType>
<xs:sequence>
<xs:element ref="kPartsPiece"  minOccurs="1" maxOccurs = "unbounded"/>
</xs:sequence>
<xs:attribute name="modelName" type="xs:NCName" use = "required"/>
</xs:complexType>
<!--piecename must be unique within kpModel-->
<xs:unique name= "kPartModel">
<xs:selector xpath="*"/>
<xs:field xpath= "@pieceName"/>
</xs:unique>
</xs:element>

<xs:element name="kPartsPiece">
<xs:complexType>
<xs:sequence>
<xs:element ref= "kPartsList"/>
</xs:sequence>         
<xs:attribute name="pieceName" type="xs:NCName"/>
<!-- if they exist previousnum and nextsnum must contain valid partNumber that is referring to a part in kpartsList-->
<xs:assert test = "every $x in data(kPartsList/*/@previousnum) satisfies some $part in kPartsList/* satisfies $part/@partNumber = $x"/>
<xs:assert test = "every $x in data(kPartsList/*/@nextsnum) satisfies some $part in kPartsList/* satisfies $part/@partNumber = $x"/>
</xs:complexType>
<!-- @partNumber is unique across kPartsList -->
<xs:unique name= "kPartsList">
<xs:selector xpath="*/*"/>
<xs:field xpath= "@partNumber"/>
</xs:unique>
</xs:element>

<xs:element name = "kPartsList" >
<xs:complexType>
<xs:sequence>
<xs:choice >
<xs:element ref = "castOnPartSeg"/>
<xs:element ref = "castOnPartPoint"/>
</xs:choice>
<xs:choice  minOccurs= "0" maxOccurs = "unbounded">
<xs:element ref = "castOnPartSeg" />
<xs:element ref = "castOnPartPoint" />
<xs:element ref = "castOffPartSeg" />
<xs:element ref = "castOffPartPoint"/>
<xs:element ref = "joinPart"/>
<xs:element ref = "splitPart" />
<xs:element ref = "segSplitPart"/>  
</xs:choice>
</xs:sequence>        
</xs:complexType>      
</xs:element>


<xs:element name="castOnPartPoint">
<xs:complexType>
<xs:attribute name ="nextsnum" type = "kpRefsList" use = "required"/>
<xs:attribute name = "partNumber" type = "xs:nonNegativeInteger" use = "required"/>
<xs:attribute name = "heightd" type = "decimal5digits" use = "required"/>
</xs:complexType>
</xs:element>

<xs:element name="castOnPartSeg">
<xs:complexType>
<xs:attribute name = "nextsnum"  type = "kpRefsList" use = "required"/>
<xs:attribute name = "partNumber" type = "xs:nonNegativeInteger" use = "required"/>
<xs:attribute name = "heightd" type = "decimal5digits" use = "required"/>
</xs:complexType>
</xs:element>


<xs:element name="castOffPartPoint">
<xs:complexType>
<xs:attribute name ="previousnum" type = "kpRefsList" use = "required"/> 
<xs:attribute name = "partNumber" type = "xs:nonNegativeInteger" use = "required"/>
<xs:attribute name = "heightd" type = "decimal5digits" fixed = "0" use = "required"/>
</xs:complexType>
</xs:element>


<xs:element name="castOffPartSeg">
<xs:complexType>
<xs:attribute name ="previousnum" type = "kpRefsList" use = "required"/> 
<xs:attribute name = "partNumber" type = "xs:nonNegativeInteger" use = "required"/>
<xs:attribute name = "heightd" type = "decimal5digits" fixed="0" use = "required"/>
</xs:complexType> 
</xs:element>


<xs:element name="splitPart">
<xs:complexType>
<xs:attribute name ="previousnum" type = "kpRefsList" use = "required"/> 
<xs:attribute name ="nextsnum" type = "kpRefsList" use = "required"/>
<xs:attribute name = "partNumber" type = "xs:nonNegativeInteger" use = "required"/>
<xs:attribute name = "heightd" type = "decimal5digits" use = "required"/>
</xs:complexType>
</xs:element>

<xs:element name="segSplitPart">
<xs:complexType>
<xs:attribute name ="previousnum"  type = "kpRefsList" use = "required"/>        
<xs:attribute name = "partNumber" type = "xs:nonNegativeInteger" use = "required"/>
<xs:attribute name = "heightd" type = "decimal5digits" fixed= "0" use = "required"/>       
</xs:complexType>
</xs:element>

<xs:element name="joinPart">
<xs:complexType>
<xs:attribute name ="nextsnum"  type = "kpRefsList" use = "required"/>   
<xs:attribute name ="previousnum" type = "kpRefsListmin2" use = "required"/>
<xs:attribute name = "partNumber" type = "xs:nonNegativeInteger" use = "required"/>
<xs:attribute name = "heightd" type = "decimal5digits" use = "required"/>      
</xs:complexType>
</xs:element>

<xs:simpleType name = "kpRefsList">
<xs:list itemType= "xs:nonNegativeInteger"/>
</xs:simpleType>

<xs:simpleType name="kpRefsListmin2"> 
<xs:restriction base = "kpRefsList"> 
<xs:minLength value = "2"/>
</xs:restriction>
</xs:simpleType>


<xs:simpleType name ="decimal5digits">
<xs:restriction base = "xs:decimal">
<xs:fractionDigits value="5"/>
</xs:restriction>
</xs:simpleType>    
</xs:schema>

传入XMLSchema Python包并正确验证实例的最终模型:

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace = "http://www.ludd21.com/kPartModel"
xmlns = "http://www.ludd21.com/kPartModel"
elementFormDefault="qualified" 
vc:minVersion = "1.1"
xpathDefaultNamespace="##targetNamespace"
xmlns:vc="http://www.w3.org/2007/XMLSchema-versioning"
>   
<xs:element name="kPartModel">
<xs:complexType>
<xs:sequence>
<xs:element ref="kPartsPiece"  minOccurs="1" maxOccurs = "unbounded"/>
</xs:sequence>
<xs:attribute name="modelName" type="xs:NCName" use = "required"/>
</xs:complexType>
<!--piecename must be unique within kpModel-->
<xs:unique name= "kPartModel">
<xs:selector xpath="*"/>
<xs:field xpath= "@pieceName"/>
</xs:unique>
</xs:element>

<xs:element name="kPartsPiece">
<xs:complexType>
<xs:sequence>
<xs:element ref= "kPartsList"/>
</xs:sequence>         
<xs:attribute name="pieceName" type="xs:NCName"/>
<!-- if they exist previousnum and nextsnum must contain valid partNumber that is referring to a part in kpartsList-->
<xs:assert id = "test-nexts" test = "every $x in data(kPartsList/*/@nextsnum) satisfies some $part in kPartsList/* satisfies $part/@partNumber = $x"/>
</xs:complexType>
<!-- @partNumber is unique across kPartsList -->
<xs:unique name= "kPartsList">
<xs:selector xpath="*/*"/>
<xs:field xpath= "@partNumber"/>
</xs:unique>
</xs:element>

<xs:element name = "kPartsList" >
<xs:complexType>
<xs:sequence>
<xs:choice >
<xs:element ref = "castOnPartSeg"/>
<xs:element ref = "castOnPartPoint"/>
</xs:choice>
<xs:choice  minOccurs= "0" maxOccurs = "unbounded">
<xs:element ref = "castOnPartSeg" />
<xs:element ref = "castOnPartPoint" />
<xs:element ref = "castOffPartSeg" />
<xs:element ref = "castOffPartPoint"/>
<xs:element ref = "joinPart"/>
<xs:element ref = "splitPart" />
<xs:element ref = "segSplitPart"/>  
</xs:choice>
</xs:sequence>        
</xs:complexType>      
</xs:element>


<xs:element name="castOnPartPoint">
<xs:complexType>
<xs:sequence>
<xs:element ref ="basePoint"/>
</xs:sequence>
<xs:attribute name ="nextsnum" type = "kpRefsList" use = "required"/>
<xs:attribute name = "partNumber" type = "xs:nonNegativeInteger" use = "required"/>
<xs:attribute name = "heightd" type = "decimal5digits" use = "required"/>
</xs:complexType>
</xs:element>

<xs:element name="castOnPartSeg">
<xs:complexType>
<xs:sequence>
<xs:element ref ="baseSeg"/>          
</xs:sequence>
<xs:attribute name = "nextsnum"  type = "kpRefsList" use = "required"/>
<xs:attribute name = "partNumber" type = "xs:nonNegativeInteger" use = "required"/>
<xs:attribute name = "heightd" type = "decimal5digits" use = "required"/>
</xs:complexType>
</xs:element>


<xs:element name="castOffPartPoint">
<xs:complexType>
<xs:sequence>
<xs:element ref ="basePoint"/>
</xs:sequence>
<xs:attribute name ="previousnum" type = "kpRefsList" use = "required"/> 
<xs:attribute name = "partNumber" type = "xs:nonNegativeInteger" use = "required"/>
<xs:attribute name = "heightd" type = "decimal5digits" fixed = "0" use = "required"/>
</xs:complexType>
</xs:element>


<xs:element name="castOffPartSeg">
<xs:complexType>
<xs:sequence>
<xs:element ref ="baseSeg"/>          
</xs:sequence>
<xs:attribute name ="previousnum" type = "kpRefsList" use = "required"/> 
<xs:attribute name = "partNumber" type = "xs:nonNegativeInteger" use = "required"/>
<xs:attribute name = "heightd" type = "decimal5digits" fixed="0" use = "required"/>
</xs:complexType> 
</xs:element>


<xs:element name="splitPart">
<xs:complexType>
<xs:sequence>
<xs:element ref ="baseSeg"/>          
</xs:sequence>
<xs:attribute name ="previousnum" type = "kpRefsList" use = "required"/> 
<xs:attribute name ="nextsnum" type = "kpRefsList" use = "required"/>
<xs:attribute name = "partNumber" type = "xs:nonNegativeInteger" use = "required"/>
<xs:attribute name = "heightd" type = "decimal5digits" use = "required"/>
</xs:complexType>
</xs:element>

<xs:element name="segSplitPart">
<xs:complexType>
<xs:sequence>
<xs:element ref ="baseSeg"/>          
</xs:sequence>
<xs:attribute name ="previousnum"  type = "kpRefsList" use = "required"/>        
<xs:attribute name = "partNumber" type = "xs:nonNegativeInteger" use = "required"/>
<xs:attribute name = "heightd" type = "decimal5digits" fixed= "0" use = "required"/>       
</xs:complexType>
</xs:element>

<xs:element name="joinPart">
<xs:complexType>
<xs:sequence>
<xs:element ref ="baseSeg"/>          
</xs:sequence>
<xs:attribute name ="nextsnum"  type = "kpRefsList" use = "required"/>   
<xs:attribute name ="previousnum" type = "kpRefsListmin2" use = "required"/>
<xs:attribute name = "partNumber" type = "xs:nonNegativeInteger" use = "required"/>
<xs:attribute name = "heightd" type = "decimal5digits" use = "required"/>      
</xs:complexType>
</xs:element>

<xs:element name = "basePoint">
<xs:complexType>
<xs:attribute name= "start" type = "point" use = "required"/>
</xs:complexType>
</xs:element>


<xs:element name = "baseSeg">
<xs:complexType>
<xs:attribute name= "start" type = "point" use = "required"/>
<xs:attribute name= "end" type = "point" use = "required"/>
<!--startY = endY!-->
<!--<xs:assert test = "@start[1] = @end[1]"/> -->
</xs:complexType>
</xs:element>

<xs:simpleType name= "point">
<xs:restriction>
<xs:simpleType>
<xs:list itemType = "decimal5digits"/>
</xs:simpleType>
<xs:length value = "2"/>
</xs:restriction>
</xs:simpleType>

<xs:simpleType name = "kpRefsList">
<xs:list itemType= "xs:nonNegativeInteger"/>
</xs:simpleType>

<xs:simpleType name="kpRefsListmin2"> 
<xs:restriction base = "kpRefsList"> 
<xs:minLength value = "2"/>
</xs:restriction>
</xs:simpleType>


<xs:simpleType name ="decimal5digits">
<xs:restriction base = "xs:decimal">
<xs:fractionDigits value="5"/>
</xs:restriction>
</xs:simpleType>    
</xs:schema>

最新更新