DFDL-декодирование перечисляемых двоичных данных - PullRequest
1 голос
/ 30 сентября 2019

В настоящее время я работаю над схемой DFDL для устаревшего (настраиваемого) двоичного формата файлов, используемого в системе для перевода в XML или JSON.

У меня есть некоторые двоичные данные, которые являются перечисляемыми значениями, то есть тип данных C-struct выглядит следующим образом (и хранится в виде байта):

typedef enum _SomeEnum
{
  ENUM_1 = 0x00,
  ENUM_2 = 0x01,
  ENUM_3 = 0x02
} SomeEnum;

Я могу декодировать перечислениек числовому значению, просто отлично с этим кодом схемы DFDL (включая проверки):

<xs:element name="SomeEnum" type="xs:unsignedByte>
  <xs:annotation>
    <xs:appinfo source="http://www.ogf.org/dfdl/">
        <dfdl:assert><![CDATA[{ . lt 3 }]]></dfdl:assert>
    </xs:appinfo>
   </xs:annotation>
</xs:element>

, который переводит в этот XML с полем enum, равным 1 в этом случае:

<SomeEnum>1</SomeEnum>

Я хотел бы иметь возможность преобразовывать декодированное значение перечисления в строку, чтобы результат XML выглядел следующим образом:

<SomeEnum>ENUM_1</SomeEnum>

, но я не уверен, как это можно сделать с помощью DFDL.

Я использую Daffodil в качестве моего синтаксического анализатора / процессора DFDL (хотя я подозреваю, что синтаксический анализатор DFDL шины интеграции IBM также сможет это сделать)

1 Ответ

1 голос
/ 30 сентября 2019

Отказ от ответственности, я разработчик Daffodil, который реализовал вариант 2 ниже.

Я не верю, что у IBM DFDL есть хорошее решение этой проблемы.

Daffodil предлагает 2 решения:

1) Использование inputValueCalc / outputValueCalc. Теория здесь заключается в том, что вы сначала анализируете перечисление как целое число (возможно, в скрытой группе), а затем используете выражения DFDL для вычисления дружественной строки в большом операторе if-else:

<xs:group name="enum">
  <xs:sequence>
    <xs:element name="enum_int" type="xs:int" dfdl:length="1" dfdl:outputValueCalc="{if (../SomeEnum eq 'ENUM_1') then 0 else if (../SomeEnum eq 'ENUM_2') then 1 else if (../SomeEnum eq 'ENUM_3') then 2 else fn:error()}"/>
  </xs:sequence>
</xs:group>

<xs:sequence>
  <xs:sequence dfdl:hiddenGroupRef="tns:enum"/>
  <xs:element name="SomeEnum" dfdl:inputValueCalc="if(../enum eq 0) then 'ENUM_1' else if(../enum eq 1) then 'ENUM_2' else if(../enum eq 2) then 'ENUM_3' else fn:error()" />
<xs:sequence>

Преимущество этогоподход заключается в том, что он полностью совместим с DFDL. Недостаток в том, что он быстро становится громоздким для больших перечислений (как для обслуживания, так и для запуска). Кроме того, насколько мне известно, Daffodil является единственным процессором DFDL, который в настоящее время поддерживает inputValueCalc и outputValueCalc, поэтому совместимость со спецификациями здесь особо не стоит.

2) Новейшая версия Daffodil (2.4. 0) включает расширение DFDL, разработанное специально для этой проблемы. Некоторая документация доступна в Daffodil wiki .

Теория здесь такова, что вы можете определить простой тип, который является ограничением для xs: string, как перечисление xsd;затем предоставьте соответствующие двоичные значения в качестве аннотации DFDL:

<xs:simpleType name="uint8" dfdl:length="1">
  <xs:restriction base="xs:unsignedInt"/>
</xs:simpleType>

<xs:simpleType name="SomeEnumType" dfdlx:repType="tns:uint8">
  <xs:restriction base="xs:string">
    <xs:enumeration value="ENUM_1" dfdlx:repValues="0" />
    <xs:enumeration value="ENUM_2" dfdlx:repValues="1" />
    <xs:enumeration value="ENUM_3" dfdlx:repValues="2" />
  </xs:restriction>
</xs:simpleType>

<xs:element name="SomeEnum" type="tns:SomeEnumType" />

Преимущество заключается в том, что схема гораздо более удобна в обслуживании, и Daffodil будет выполнять поиск, используя прямой поиск в хеш-таблицах, вместо необходимостипройти сквозь другое дерево.

...