Search code examples
xmlloopsxsdassert

Looping XSD 1.1 assert


I'm doing my best to validate XML document with XSD 1.1 schema but there's no way. I've simplified my sample and looks like this:

<?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">
    <xs:element name="message1">
        <xs:complexType>
            <xs:sequence>
                <xs:element type="xs:string" name="indexmessage"/>
                <xs:element name="rows" maxOccurs="1">
                    <xs:complexType>
                        <xs:sequence>
                            <xs:element name="row" minOccurs="1" maxOccurs="unbounded">
                                <xs:complexType>
                                    <xs:sequence>
                                        <xs:element name="code">
                                            <xs:simpleType>
                                                <xs:restriction base="xs:string">
                                                    <xs:minLength value="1"/>
                                                    <xs:maxLength value="16"/>
                                                </xs:restriction>
                                            </xs:simpleType>
                                        </xs:element>
                                        <xs:element name="totalquantity">
                                            <xs:simpleType>
                                                <xs:restriction base="xs:decimal">
                                                    <xs:fractionDigits value="2"/>
                                                </xs:restriction>
                                            </xs:simpleType>
                                        </xs:element>
                                        <xs:element name="attachments" minOccurs="0" maxOccurs="1">
                                            <xs:complexType>
                                                <xs:sequence>
                                                    <xs:element name="attachment" minOccurs="1"
                                                  maxOccurs="unbounded">
                                                        <xs:complexType>
                                                            <xs:sequence>
                                                                <xs:element name="quantity">
                                                                    <xs:simpleType>
                                                                        <xs:restriction base="xs:decimal">
                                                                            <xs:fractionDigits value="2"/>
                                                                        </xs:restriction>
                                                                    </xs:simpleType>
                                                                </xs:element>
                                                            </xs:sequence>
                                                        </xs:complexType>
                                                    </xs:element>
                                                </xs:sequence>                                                                                              
                                            </xs:complexType>
                                        </xs:element>
                                    </xs:sequence>                                  
                                    <xs:assert test="every $r in row/attachments/attachment satisfies eq(row/quantitytotal, sum($r/quantity)"/>
                                </xs:complexType>
                            </xs:element>
                        </xs:sequence>
                    </xs:complexType>
                </xs:element>
            </xs:sequence>
        </xs:complexType>
    </xs:element>
</xs:schema>

So what I want to implement in xs:assertion is that quantitytotal must be equals to the sum of the quantity of "row attachments". I've seen many samples using "every" keyword but never works. Here's an XSD sample also:

<?xml version="1.0" encoding="UTF-8"?>
<message1>                  
    <indexmessage>02</indexmessage>     
    <rows>              
        <row>           
            <code>1789</code>       
            <totalquantity>3</totalquantity>
            <attachments>
                <attachment>
                    <quantity>2</quantity>
                </attachment>
                <attachment>
                    <quantity>1</quantity>
                </attachment>
            </attachments>
        </row>
        <row>
         ...
        </row>              
    </rows>             
</message1>

Assert in this sample must be true cause 2+1=3 and it's the reason why I'm trying to implement xs:assert looping all rows.

Many thanks ;)


Solution

  • You don't need to "loop" through row elements. Your assertion is at the row level already; from there, let sum() add all the quantity values:

    <xs:assert test="sum(attachments/attachment/quantity) = totalquantity"/>
    

    This assertion will be checked for each row automatically.

    Here is the above assertion in context in your XSD:

    <?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" 
               vc:minVersion="1.1" 
               elementFormDefault="qualified">
      <xs:element name="message1">
        <xs:complexType>
          <xs:sequence>
            <xs:element type="xs:string" name="indexmessage"/>
            <xs:element name="rows" maxOccurs="1">
              <xs:complexType>
                <xs:sequence>
                  <xs:element name="row" minOccurs="1" maxOccurs="unbounded">
                    <xs:complexType>
                      <xs:sequence>
                        <xs:element name="code">
                          <xs:simpleType>
                            <xs:restriction base="xs:string">
                              <xs:minLength value="1"/>
                              <xs:maxLength value="16"/>
                            </xs:restriction>
                          </xs:simpleType>
                        </xs:element>
                        <xs:element name="totalquantity">
                          <xs:simpleType>
                            <xs:restriction base="xs:decimal">
                              <xs:fractionDigits value="2"/>
                            </xs:restriction>
                          </xs:simpleType>
                        </xs:element>
                        <xs:element name="attachments" minOccurs="0" maxOccurs="1">
                          <xs:complexType>
                            <xs:sequence>
                              <xs:element name="attachment" minOccurs="1"
                                          maxOccurs="unbounded">
                                <xs:complexType>
                                  <xs:sequence>
                                    <xs:element name="quantity">
                                      <xs:simpleType>
                                        <xs:restriction base="xs:decimal">
                                          <xs:fractionDigits value="2"/>
                                        </xs:restriction>
                                      </xs:simpleType>
                                    </xs:element>
                                  </xs:sequence>
                                </xs:complexType>
                              </xs:element>
                            </xs:sequence>                                                                                              
                          </xs:complexType>
                        </xs:element>
                      </xs:sequence>                                  
                      <xs:assert test="sum(attachments/attachment/quantity) = totalquantity"/>
                    </xs:complexType>
                  </xs:element>
                </xs:sequence>
              </xs:complexType>
            </xs:element>
          </xs:sequence>
        </xs:complexType>
      </xs:element>
    </xs:schema>