You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@daffodil.apache.org by Christofer Dutz <ch...@c-ware.de> on 2019/05/07 07:40:37 UTC

What is the right way to define constants?

Hi,

in our PLC4X project we have several places where there are bytes with fixed values expected.
How would be the right was to define that?

So a S7 protocol message would always start with a byte with the value 0x32 … simply modeling that as a byte would make a packet with 0x42 also valid, which is not the case.

So how do I force the byte value to be exactly a pre-defined value?

Chris

Re: What is the right way to define constants?

Posted by Christofer Dutz <ch...@c-ware.de>.
Ah ok ... thanks for those infos ...

Guess I had things almost right from the start as I was using fixed, but thought it didn't apply as it was still succeeding __

I'll let those infos flow into my schemas.

Thanks,
      Chris


Am 07.05.19, 13:49 schrieb "Steve Lawrence" <sl...@apache.org>:

    There's a couple ways to do this in DFDL.
    
    One way is with the XSD "fixed" facet. So something like:
    
      <xs:element name="field" type="xs:byte" fixed="50" ... />
    
    The fixed attribute is only checked when validation is enabled. If so,
    and "field" does not match the value of the fixed facet, parsing will
    still continue as normal, but validation errors will be reported at the
    end of parsing. The benefit of this is that if "field" isn't valid with
    respect to the facet, you will still get an infoset. So if everything
    else about the data is correct and "well-formed" but not valid, you can
    potentially recover. Unfortunately, Daffodil does not support this facet
    yet (DAFFODIL-117). But you can achieve the same functionality using
    xs:restriction:
    
      <xs:element name="field" ...>
        <xs:simpleType>
          <xs:restriction type="xs:byte">
            <xs:minInclusive value="50" />
            <xs:maxInclusive value="50" />
          </xs:restriction>
        </xs:simpleType>
      </xs:element>
    
    This is essentially the same thing as using fixed, just not as concise.
    
    
    A different method with a different behavior is to use dfdl:assert to
    check the value after it has been parsed:
    
      <xs:element name="field" type="xs:byte" ...>
        <xs:annotation>
          <xs:appinfo source="http://www.ogf.org/dfdl/">
            <dfdl:assert test="{ . eq 50 }" />
          </xs:appinfo>
        </xs:annotation>
      </xs:element>
    
    In this case, the assert test is performed at parse time immediately
    after field is parsed. If field is not the correct value, the failed
    assert will immediately result in an ParseError and Daffodil will
    backtrack, which could lead to a parse failure and no infoset. If you
    want the parse to fail when fields are invalid, this is the route to take.
    
    Also, note that assertions are not checked when unparsing--Daffodil will
    just unparse whatever value is in the infoset. If you also want to
    ensure the value is constant on unparsing, you can either manually
    modify the infoset before unparsing if it's not the right value, or use
    dfdl:outputValueCalc to have Daffodil unparse a different value than
    what is in the infoset:
    
      <xs:element name="field" type="xs:byte" dfdl:outputValueCalc="{ 50 }"
    ... />
    
    - Steve
    
    
    On 5/7/19 3:40 AM, Christofer Dutz wrote:
    > Hi,
    > 
    > in our PLC4X project we have several places where there are bytes with fixed 
    > values expected.
    > 
    > How would be the right was to define that?
    > 
    > So a S7 protocol message would always start with a byte with the value 0x32 … 
    > simply modeling that as a byte would make a packet with 0x42 also valid, which 
    > is not the case.
    > 
    > So how do I force the byte value to be exactly a pre-defined value?
    > 
    > Chris
    > 
    
    


Re: What is the right way to define constants?

Posted by Steve Lawrence <sl...@apache.org>.
There's a couple ways to do this in DFDL.

One way is with the XSD "fixed" facet. So something like:

  <xs:element name="field" type="xs:byte" fixed="50" ... />

The fixed attribute is only checked when validation is enabled. If so,
and "field" does not match the value of the fixed facet, parsing will
still continue as normal, but validation errors will be reported at the
end of parsing. The benefit of this is that if "field" isn't valid with
respect to the facet, you will still get an infoset. So if everything
else about the data is correct and "well-formed" but not valid, you can
potentially recover. Unfortunately, Daffodil does not support this facet
yet (DAFFODIL-117). But you can achieve the same functionality using
xs:restriction:

  <xs:element name="field" ...>
    <xs:simpleType>
      <xs:restriction type="xs:byte">
        <xs:minInclusive value="50" />
        <xs:maxInclusive value="50" />
      </xs:restriction>
    </xs:simpleType>
  </xs:element>

This is essentially the same thing as using fixed, just not as concise.


A different method with a different behavior is to use dfdl:assert to
check the value after it has been parsed:

  <xs:element name="field" type="xs:byte" ...>
    <xs:annotation>
      <xs:appinfo source="http://www.ogf.org/dfdl/">
        <dfdl:assert test="{ . eq 50 }" />
      </xs:appinfo>
    </xs:annotation>
  </xs:element>

In this case, the assert test is performed at parse time immediately
after field is parsed. If field is not the correct value, the failed
assert will immediately result in an ParseError and Daffodil will
backtrack, which could lead to a parse failure and no infoset. If you
want the parse to fail when fields are invalid, this is the route to take.

Also, note that assertions are not checked when unparsing--Daffodil will
just unparse whatever value is in the infoset. If you also want to
ensure the value is constant on unparsing, you can either manually
modify the infoset before unparsing if it's not the right value, or use
dfdl:outputValueCalc to have Daffodil unparse a different value than
what is in the infoset:

  <xs:element name="field" type="xs:byte" dfdl:outputValueCalc="{ 50 }"
... />

- Steve


On 5/7/19 3:40 AM, Christofer Dutz wrote:
> Hi,
> 
> in our PLC4X project we have several places where there are bytes with fixed 
> values expected.
> 
> How would be the right was to define that?
> 
> So a S7 protocol message would always start with a byte with the value 0x32 … 
> simply modeling that as a byte would make a packet with 0x42 also valid, which 
> is not the case.
> 
> So how do I force the byte value to be exactly a pre-defined value?
> 
> Chris
>