Hi all,

thanks for all of your help ... I am coming closer and closer to a first fully 
operational DFDL schema for S7 communication ... really looking forward to 
experimenting with that.

Now I ran into something probably quite special:

In my messages I have a header, parameters and payloads
While each payload has a "type" indicator, the payloads don't. The payloads are 
somewhat parsed by iterating over the previously parsed parameters and for each 
parameter (in exactly the same order) create a payload.
However not all parameters have payloads ... 

So here's what I've come up so far:

    <xs:element name="S7ResponseMessage">
        <xs:complexType>
            <xs:sequence>
                <!-- Reserved value always 0x0000 -->
                <xs:element name="reserved" type="s7:short" fixed="0"/>
                <xs:element name="tpduReference" type="s7:short"/>
                <xs:element name="parametersLength" type="s7:short"/>
                <xs:element name="payloadsLength" type="s7:short"/>
                <!-- UserData (type 7) responses don't have the error class and 
code -->
                <xs:element name="errorClass" type="s7:byte" minOccurs="0"
                            dfdl:occursCountKind="expression" 
dfdl:occursCount="{if(../../type eq 3) then 1 else 0}"/>
                <xs:element name="errorCode" type="s7:byte" minOccurs="0"
                            dfdl:occursCountKind="expression" 
dfdl:occursCount="{if(../../type eq 3) then 1 else 0}"/>
                <xs:element name="parameters" minOccurs="0"
                            dfdl:lengthKind="explicit" dfdl:lengthUnits="bytes" 
dfdl:length="{../parametersLength}"
                            dfdl:occursCountKind="expression" 
dfdl:occursCount="{if(../parametersLength gt 0) then 1 else 0}">
                    <xs:complexType>
                        <xs:sequence>
                            <xs:element name="parameter" maxOccurs="unbounded">
                                <xs:complexType>
                                    <xs:sequence>
                                        <xs:element name="type" type="s7:byte"/>
                                        <xs:choice 
dfdl:choiceDispatchKey="{type}">
                                            <xs:element 
dfdl:choiceBranchKey="240" ref="s7:S7GeneralParameterSetupCommunication"/>
                                            <xs:element 
dfdl:choiceBranchKey="0" ref="s7:S7ResponseParameterCPUService"/>
                                            <xs:element 
dfdl:choiceBranchKey="4" ref="s7:S7ResponseParameterReadVar"/>
                                            <xs:element 
dfdl:choiceBranchKey="5" ref="s7:S7ResponseParameterWriteVar"/>
                                        </xs:choice>
                                    </xs:sequence>
                                </xs:complexType>
                            </xs:element>
                        </xs:sequence>
                    </xs:complexType>
                </xs:element>
                <xs:element name="payloads" minOccurs="0"
                            dfdl:lengthKind="explicit" dfdl:lengthUnits="bytes" 
dfdl:length="{../payloadsLength}"
                            dfdl:occursCountKind="expression" 
dfdl:occursCount="{if(../payloadsLength gt 0) then 1 else 0}">
                    <xs:complexType>
                        <xs:sequence>
                            <xs:element name="payload" maxOccurs="unbounded"
                                        dfdl:occursCountKind="expression" 
dfdl:occursCount="{count(../parameters/parameter)}">
                                <xs:complexType>
                                    <!-- TODO: Somehow loop over the parameters 
and use those elements as type keys -->
                                    <xs:sequence>
                                        <xs:element name="type" type="s7:byte"/>
                                        <xs:choice 
dfdl:choiceDispatchKey="{type}">
                                            <xs:element 
dfdl:choiceBranchKey="0" ref="s7:S7ResponsePayloadCpuServices"/>
                                            <xs:element 
dfdl:choiceBranchKey="4" ref="s7:S7ResponsePayloadReadVar"/>
                                            <xs:element 
dfdl:choiceBranchKey="5" ref="s7:S7ResponsePayloadWriteVar"/>
                                        </xs:choice>
                                    </xs:sequence>
                                </xs:complexType>
                            </xs:element>
                        </xs:sequence>
                    </xs:complexType>
                </xs:element>
            </xs:sequence>
        </xs:complexType>
    </xs:element>

So the "payload" element should occur exactly as often as there are parameters. 
Now I was thinking that if for a parameter there is no matching payload, I'll 
just not output any or just some dummy output.
The problem however is, how can I iterate over the parameters and for each get 
the "type" and depending on that select the right choice branch?

Chris


Am 16.01.19, 02:08 schrieb "Beckerle, Mike" <[email protected]>:

    Christofer,
    
    
    So in DFDL, unlike regular XSD, only elements can be repeating/optional.
    
    
    You can't have max/minOccurs on a choice or sequence, only on an element.
    
    
    DFDL isn't only for XML. Many data models that the DFDL infoset could be 
projected into, those data models don't allow repeating or optional  entities 
that aren't named and unitary.
    
    
    If we had allowed repeating anonymous groups, then if you interfaced DFDL 
directly to a language with tthis, we'd be having to generate names for these 
anonymous groups. We decided instead to keep the data model for DFDL simpler. 
If it repeats or is optional it has to be an element.
    
    
    The rationale here is the same reason we left out attributes of XSD. DFDL 
has only elements. This is because this dual-child tree where a node can have 
element children AND attribute children that have the same names that do not 
get mixed up... that's unique to XML, and DFDL is trying to be not so tied to 
XML/XSD, but able to describe data and project that data into the native data 
structures of many data models.
    
    
    ...mike beckerle
    
    Tresys Technology
    
    
    ________________________________
    From: Christofer Dutz <[email protected]>
    Sent: Tuesday, January 15, 2019 4:15:26 PM
    To: [email protected]
    Subject: Re: Daffodil ignoring dfdl:length=0 when dfdl:lengthKind=explicit
    
    (Wonder why every response turns out to be a private off-list response ... 
gotta remember to hit "reply to all")
    
    Thanks guys ... that worked like a charm ;-)
    
    Now I stumbled into the next little problem I couldn't find any 
documentation on.
    
    Now I have two situations:
    1) The "parameterLength" provides the number of bytes all parameters 
consume, so the parser should continue parsing parameters as long as there are 
bytes left to read.
    How can I tell the sequence or the choice allow multiple instances?
    
    2) I have "numItems" specifying the number of item-elements (also different 
types) so here not the number of bytes controls how many items are parsed, but 
the plain number of elements.
    Here too I cant find a way to specify a xs:minOccurs, xs:maxOccurs or 
dfdl:occursCount ... all seem to be invalid for both sequence and choice.
    
    Chris
    
    Am 15.01.19, 18:52 schrieb "Steve Lawrence" <[email protected]>:
    
        It's not that Daffodil is ignoring dfdl:lengthKind="0", it's just that
        is allows length of zero to be valid. There are actually some use cases
        where zero length is valid, and you would want this to cause a backtrack
        if the children required more than zero bytes.
    
        In this case, you just need to make it so that if the length is zero
        then it does not attempt to parse any child elements. One way to
        accomplish this is via dfdl:occursCountKind="expression" and
        dfdl:occursCount, something like so:
    
          <xs:element name="payloads" minOccurs="0" maxOccurs="1
            dfdl:lengthKind="explicit" dfdl:lengthUnits="bytes"
            dfdl:length="{../payloadsLength }"
            dfdl:occursCountKind="expression" dfdl:occursCount="{
          if (../payloadsLength eq 0) then 0 else 1
          }"
            <xs:complexType>
              <xs:sequence>
                <xs:choice>
                  <xs:element ref="s7:S7RequestPayloadCpuServices"/>
                  <xs:element ref="s7:S7RequestPayloadWriteVar"/>
                </xs:choice>
              </xs:sequence>
            </xs:complexType>
          </xs:element>
    
        This changes the payloads element to be optional (minOccurs=0) and
        defines the occurrences as either 0 or 1 based on the value of the
        payloadsLength. If the length is 1, the payloads element will not exist
        in the infoset and it will not attempt to parse the child data.
    
        - Steve
    
    
    
        On 1/15/19 10:39 AM, Christofer Dutz wrote:
        > Hi all,
        >
        > after working though the 6 tutorials on DFDL in general I think I 
have a much greater understanding on how I have to do things. I even managed to 
get my S7 protocol messages schema in a somewhat working condition.
        > Right now I’m having one problem:
        > A S7 Messages consists of a header, a number of variable length 
parameters and a number of variable length payloads.
        > As parameters and payloads are of variable length, the header 
contains a “parametersLength” and “payloadsLength” field which contains the 
number of bytes the parameters and payloads require in total.
        > So I defined something like this:
        >
        >
        > <xs:element name="parametersLength" type="s7:short"/>
        > <xs:element name="payloadsLength" type="s7:short"/>
        > <xs:element name="parameters" dfdl:lengthKind="explicit" 
dfdl:lengthUnits="bytes" dfdl:length="{../parametersLength}">
        >     <xs:complexType>
        >         <xs:sequence>
        >             <xs:choice>
        >                 <xs:element 
ref="s7:S7GeneralParameterSetupCommunication"/>
        >                 <xs:element ref="s7:SS7RequestParameterCPUService"/>
        >                 <xs:element ref="s7:S7RequestParameterReadVar"/>
        >                 <xs:element ref="s7:S7RequestParameterWriteVar"/>
        >             </xs:choice>
        >         </xs:sequence>
        >     </xs:complexType>
        > </xs:element>
        > <xs:element name="payloads" dfdl:lengthKind="explicit" 
dfdl:lengthUnits="bytes" dfdl:length="{../payloadsLength}">
        >     <xs:complexType>
        >         <xs:sequence>
        >             <xs:choice>
        >                 <xs:element ref="s7:S7RequestPayloadCpuServices"/>
        >                 <xs:element ref="s7:S7RequestPayloadWriteVar"/>
        >             </xs:choice>
        >         </xs:sequence>
        >     </xs:complexType>
        > </xs:element>
        >
        > However in a request, that doesn’t contain any payloads, daffodil 
still tries to parse the payloads, even if the “length” of the sequence is set 
to explicit and to a length of 0 … why is it doing that?
        > Each parameter and payloads first byte contains the code that tells 
the parser what type it is and each of the elements in my schema use a 
discriminator to tell the parser which input it is requiring.
        >
        >
        > <xs:element name="S7RequestPayloadCpuServices">
        >     <xs:annotation>
        >         <xs:appinfo source="http://www.ogf.org/dfdl/";>
        >             <dfdl:discriminator test="{./type eq 0}"/>
        >         </xs:appinfo>
        >     </xs:annotation>
        >     <xs:complexType>
        >         <xs:sequence>
        >             <xs:element name="type" type="s7:byte"/>
        >             <xs:element name="transportSize" type="s7:byte"/><!-- 
fixed="9"-->
        >             <xs:element name="length" type="s7:byte"/>
        >             <xs:element name="sslId" type="s7:short"/>
        >             <xs:element name="sslIndex" type="s7:short"/>
        >         </xs:sequence>
        >     </xs:complexType>
        > </xs:element>
        >
        > Hope it’s correct to do things like that …
        >
        > The effect is that Daffodil has correctly parsed all the parameters 
and as there is no payload (payloadLength = 0) it shouldn’t try to parse a 
payload, but it does and when reading the first byte it instantly fails as 
there is no data to parse anymore.
        >
        >
        > Chris
        >
    
    
    
    

Reply via email to