-->

Optional/mandatory element based on non-sibling el

2019-07-31 11:15发布

问题:

I am trying to apply validation of mandatory and optional on one element of XML which is depending upon value of other element.

Below is 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">

<xs:element name="root" type="root"></xs:element>

<xs:complexType name="root">
    <xs:sequence>
        <xs:element name="P1Message"
            type="p1Message">
        </xs:element>
    </xs:sequence>
</xs:complexType>

<xs:complexType name="p1Message">
    <xs:sequence>
        <xs:element name="Hdr" type="hdr"></xs:element>
        <xs:element name="Inf" type="inf"></xs:element>         
    </xs:sequence>
</xs:complexType>

<xs:complexType name="hdr">
    <xs:sequence>
        <xs:element name="I1Agt" type="i1Agt"></xs:element>
        <xs:element name="SequenceNum" type="xs:string"></xs:element>
        <xs:element name="SessionNum" type="xs:string"></xs:element>        
        <xs:element name="MsgTyp" type="xs:string"></xs:element>                
        <xs:element name="IntComment" type="xs:string"></xs:element>
    </xs:sequence>  
<xs:assert test="LclInstrm or not(MsgTyp = '103')"/>    
</xs:complexType>

<xs:complexType name="i1Agt">
    <xs:sequence>
        <xs:element name="FinInstnId" type="finInstnId"></xs:element>
    </xs:sequence>
</xs:complexType>

<xs:complexType name="finInstnId">
    <xs:sequence>
        <xs:element name="B1" type="xs:string"></xs:element>
    </xs:sequence>
</xs:complexType>

<xs:complexType name="inf">
    <xs:sequence>           
        <xs:element name="PmtTpInf" type="pmtTpInf"></xs:element>           
    </xs:sequence>
</xs:complexType>

<xs:complexType name="pmtTpInf">
    <xs:sequence>
        <xs:element name="LclInstrm" type="xs:string" minOccurs="0" maxOccurs="1"></xs:element>
        <xs:element name="Svc" type="svc"></xs:element>
    </xs:sequence>     
</xs:complexType>

<xs:complexType name="svc">
    <xs:sequence>
        <xs:element name="Cd" type="xs:string"></xs:element>
    </xs:sequence>
</xs:complexType>
</xs:schema>

Below is XML:

<?xml version="1.0" encoding="utf-8"?>
<root>
<P1Message>
<Hdr>
  <I1Agt>
    <FinInstnId>
      <B1>str1234</B1>
    </FinInstnId>
  </I1Agt>
  <SequenceNum>str1234</SequenceNum>
  <SessionNum>str1234</SessionNum>
  <MsgTyp>123</MsgTyp>
  <IntComment>str1234</IntComment>
</Hdr>
<Inf>
   <PmtTpInf>
    <LclInstrm>str1234</LclInstrm>
    <Svc>
      <Cd>str1234</Cd>
    </Svc>
  </PmtTpInf>
</Inf>
</P1Message>
</root>

I want to make LclInstrm element mandatory when value of MsgTyp is 103.

When I am trying to validate above XML with XSD in Java I am getting below error:

message.xml is not valid because cvc-assertion.3.13.4.1: Assertion evaluation ('LclInstrm or not(MsgTyp = '103')') for element `Hdr` with type `hdr` did not succeed.

could anyone please help me with same?

Please let me know if you require more details.

回答1:

Your XPath in the assertion is off because it's assuming that LclInstrm and MsgTyp are siblings when they're not.

Your assertion will have to go on a common ancestor (P1Message) and reference the correct relative paths to each element.

So, your assertion on P1Message would be:

<xs:assert test="Inf/PmtTpInf/LclInstrm or not(Hdr/MsgTyp = '103')"/>

Another working example of how to use an assertion to conditionally require an element based upon the value of another element can be found here: Require XML element in XSD when another element has certain value?