This looks really good to me and should have pretty good performance.

I would make one minor suggestion, which is to change your payload
choiceDispatchKey expression from:

  {../../parameters[1]/parameter[fn:count(../payload)]/type}

to

  {../../parameters[1]/parameter[dfdl:occursIndex()]/type}

So use the dfdl:occursIndex() function to find the associated parameter
instead of the fn:count() function. The dfdl:occursIndex() function
returns the index of the current array, which in this context is the
payload array. This is functionally the same as fn:count(../payload),
but dfdl:occursIndex() should be a bit more efficient. This is because
fn:count(../payload) needs to evaluate the ../payload path to find the
payload array and then count the number of elements, whereas
dfdl:occursIndex() can access internal state to know the exact current
index in constant time.

- Steve



On 1/16/19 7:28 AM, Christofer Dutz wrote:
> Hi all,
> 
> I think I found a solution on my own ... the key is that I now output an 
> payload element for every parameter, even if that is empty in some cases, 
> with this, I was able to do the following:
> 
>     <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) or (../parametersLength gt 0)) 
> then 1 else 0}">
>                     <xs:complexType>
>                         <xs:sequence>
>                             <xs:element name="payload" maxOccurs="unbounded"
>                                         dfdl:occursCountKind="expression" 
> dfdl:occursCount="{fn:count(../../parameters[1]/parameter)}">
>                                 <xs:complexType>
>                                     <xs:sequence>
>                                         <xs:choice 
> dfdl:choiceDispatchKey="{../../parameters[1]/parameter[fn:count(../payload)]/type}">
>                                             <xs:element 
> dfdl:choiceBranchKey="240" ref="s7:S7GeneralPayloadSetupCommunication"/>
>                                             <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 what I do now is that I use the type-element of the matching parameter for 
> the second decision.
> 
> However I would like to report, das not even by debugging the code was I able 
> to understand the error message about not supporting arrays.
> "Query-style paths not supported. Must have '[...]' after array-element's 
> name."
> Cause the real reason is that the problem was that on the up-path only the 
> last part can exist without the array notation and in this case the 
> intermediate "parameters" fragment had to be added an array index.
> 
> How is the above solution performance-wise?
> 
> Chris
> 
> 
> 
> Am 16.01.19, 11:54 schrieb "Christofer Dutz" <[email protected]>:
> 
>     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