разбирать текстовый файл фиксированной длины с XSLT 2.0 - PullRequest
0 голосов
/ 15 ноября 2018

У меня есть некоторые текстовые файлы фиксированной длины для обработки, и выход должен быть структурированным XML-файлом.Формат этих текстовых файлов указан в XML.

Тримические части:

  • Спецификация формата содержит вложенную структуру (элемент StructFormat может содержать StructFormat)
  • структура может повторяться (используйте атрибут repeat StructFormat, например repeat='4').

Вот пример спецификации формата:

<?xml version='1.0' encoding='windows-1252'?>
<MessageFormat name='NewMessageFormat' version='2.02'>
<FieldFormat name='G-TRA-MESSAGE-ID' type='String' delimOptional='y' length='18' strlenInChars='y' trimLeading=' ' trimTrailing=' '/>
    <StructFormat name='G-TAFT-HEAD-DAT' delimOptional='y'>
        <FieldFormat name='G-AFT-FIP-DATUM' type='String' delimOptional='y' length='10' strlenInChars='y' trimLeading=' ' trimTrailing=' '/>
        <FieldFormat name='G-AFT-FIP-ZEIT' type='String' delimOptional='y' length='8' strlenInChars='y' trimLeading=' ' trimTrailing=' '/>
    </StructFormat>
    <StructFormat name='G-TAFT-KUNDEN' delimOptional='y' repeat='2'>
        <FieldFormat name='G-AKU-LDSGVNR' type='String' delimOptional='y' length='6' strlenInChars='y' trimLeading=' ' trimTrailing=' '/>
        <FieldFormat name='G-AKU-KDSGVNR' type='String' delimOptional='y' length='10' strlenInChars='y' trimLeading=' ' trimTrailing=' '/>
    </StructFormat>
    <StructFormat name='G-TFGB-WGN-AN-LB' delimOptional='y' repeat='3'>
        <FieldFormat name='G-ZA-WGN-FUNK-CODE' type='String' delimOptional='y' length='1' strlenInChars='y' trimLeading=' ' trimTrailing=' '/>
        <FieldFormat name='G-FGB-WGN-RIV-CODE' type='String' delimOptional='y' length='2' strlenInChars='y' pad='0' padType='leading' trimLeading=' ' trimTrailing=' '/>
        <StructFormat name='G-FSB-SONDERBEH-CD' delimOptional='y' repeat='5'>
            <FieldFormat name='G-FSB-SONDERBEH-CD' type='String' delimOptional='y' length='2' strlenInChars='y' trimLeading=' ' trimTrailing=' '/>
        </StructFormat>
        <StructFormat name='G-TFGB-GUT-AN-LB' delimOptional='y' repeat='4'>
            <FieldFormat name='G-FGB-GGT-ZETT-NR-1' type='String' delimOptional='y' length='4' strlenInChars='y' trimLeading=' ' trimTrailing=' '/>
            <FieldFormat name='G-FGB-GGT-ZETT-NR-2' type='String' delimOptional='y' length='4' strlenInChars='y' trimLeading=' ' trimTrailing=' '/>
            <FieldFormat name='G-FGB-GGT-ZETT-NR-3' type='String' delimOptional='y' length='4' strlenInChars='y' trimLeading=' ' trimTrailing=' '/>
        </StructFormat>
        <FieldFormat name='G-FBD-PRIO-KENNZ' type='String' delimOptional='y' length='1' strlenInChars='y' trimLeading=' ' trimTrailing=' '/>
    </StructFormat>
    </MessageFormat>

И образец текста:

G-TRA-MESSAGE-ID  G-AFT-FIP-G-AFT-FIG-AKU-G-AKU-KDSGG-AKU-G-AKU-KDSGGG-G-G-G-G-G-G-FGG-FGG-FGG-FGG-FGG-FGG-FGG-FGG-FGG-FGG-FGG-FGGGG-G-G-G-G-G-G-FGG-FGG-FGG-FGG-FGG-FGG-FGG-FGG-FGG-FGG-FGG-FGGGG-G-G-G-G-G-G-FGG-FGG-FGG-FGG-FGG-FGG-FGG-FGG-FGG-FGG-FGG-FGG

Таким образом, ожидаемый результат должен быть следующим:

<?xml version="1.0" encoding="UTF-8"?>
<NewMessageFormat>
<G-TRA-MESSAGE-ID>G-TRA-MESSAGE-ID</G-TRA-MESSAGE-ID>
<G-TAFT-HEAD-DAT>
    <G-AFT-FIP-DATUM>G-AFT-FIP-</G-AFT-FIP-DATUM>
    <G-AFT-FIP-ZEIT>G-AFT-FI</G-AFT-FIP-ZEIT>
</G-TAFT-HEAD-DAT>
<G-TAFT-KUNDEN>
    <G-AKU-LDSGVNR>G-AKU-</G-AKU-LDSGVNR>
    <G-AKU-KDSGVNR>G-AKU-KDSG</G-AKU-KDSGVNR>
</G-TAFT-KUNDEN>
<G-TAFT-KUNDEN>
    <G-AKU-LDSGVNR>G-AKU-</G-AKU-LDSGVNR>
    <G-AKU-KDSGVNR>G-AKU-KDSG</G-AKU-KDSGVNR>
</G-TAFT-KUNDEN>
<G-TFGB-WGN-AN-LB>
    <G-ZA-WGN-FUNK-CODE>G</G-ZA-WGN-FUNK-CODE>
    <G-FGB-WGN-RIV-CODE>G-</G-FGB-WGN-RIV-CODE>
    <G-FSB-SONDERBEH-CD>
    <G-FSB-SONDERBEH-CD>G-</G-FSB-SONDERBEH-CD>
    </G-FSB-SONDERBEH-CD>
    <G-FSB-SONDERBEH-CD>
    <G-FSB-SONDERBEH-CD>G-</G-FSB-SONDERBEH-CD>
    </G-FSB-SONDERBEH-CD>
    <G-FSB-SONDERBEH-CD>
    <G-FSB-SONDERBEH-CD>G-</G-FSB-SONDERBEH-CD>
    </G-FSB-SONDERBEH-CD>
    <G-FSB-SONDERBEH-CD>
    <G-FSB-SONDERBEH-CD>G-</G-FSB-SONDERBEH-CD>
    </G-FSB-SONDERBEH-CD>
    <G-FSB-SONDERBEH-CD>
    <G-FSB-SONDERBEH-CD>G-</G-FSB-SONDERBEH-CD>
    </G-FSB-SONDERBEH-CD>
    <G-TFGB-GUT-AN-LB>
    <G-FGB-GGT-ZETT-NR-1>G-FG</G-FGB-GGT-ZETT-NR-1>
    <G-FGB-GGT-ZETT-NR-2>G-FG</G-FGB-GGT-ZETT-NR-2>
    <G-FGB-GGT-ZETT-NR-3>G-FG</G-FGB-GGT-ZETT-NR-3>
    </G-TFGB-GUT-AN-LB>
    <G-TFGB-GUT-AN-LB>
    <G-FGB-GGT-ZETT-NR-1>G-FG</G-FGB-GGT-ZETT-NR-1>
    <G-FGB-GGT-ZETT-NR-2>G-FG</G-FGB-GGT-ZETT-NR-2>
    <G-FGB-GGT-ZETT-NR-3>G-FG</G-FGB-GGT-ZETT-NR-3>
    </G-TFGB-GUT-AN-LB>
    <G-TFGB-GUT-AN-LB>
    <G-FGB-GGT-ZETT-NR-1>G-FG</G-FGB-GGT-ZETT-NR-1>
    <G-FGB-GGT-ZETT-NR-2>G-FG</G-FGB-GGT-ZETT-NR-2>
    <G-FGB-GGT-ZETT-NR-3>G-FG</G-FGB-GGT-ZETT-NR-3>
    </G-TFGB-GUT-AN-LB>
    <G-TFGB-GUT-AN-LB>
    <G-FGB-GGT-ZETT-NR-1>G-FG</G-FGB-GGT-ZETT-NR-1>
    <G-FGB-GGT-ZETT-NR-2>G-FG</G-FGB-GGT-ZETT-NR-2>
    <G-FGB-GGT-ZETT-NR-3>G-FG</G-FGB-GGT-ZETT-NR-3>
    </G-TFGB-GUT-AN-LB>
    <G-FBD-PRIO-KENNZ>G</G-FBD-PRIO-KENNZ>
</G-TFGB-WGN-AN-LB>
<G-TFGB-WGN-AN-LB>
    <G-ZA-WGN-FUNK-CODE>G</G-ZA-WGN-FUNK-CODE>
    <G-FGB-WGN-RIV-CODE>G-</G-FGB-WGN-RIV-CODE>
    <G-FSB-SONDERBEH-CD>
    <G-FSB-SONDERBEH-CD>G-</G-FSB-SONDERBEH-CD>
    </G-FSB-SONDERBEH-CD>
    <G-FSB-SONDERBEH-CD>
    <G-FSB-SONDERBEH-CD>G-</G-FSB-SONDERBEH-CD>
    </G-FSB-SONDERBEH-CD>
    <G-FSB-SONDERBEH-CD>
    <G-FSB-SONDERBEH-CD>G-</G-FSB-SONDERBEH-CD>
    </G-FSB-SONDERBEH-CD>
    <G-FSB-SONDERBEH-CD>
    <G-FSB-SONDERBEH-CD>G-</G-FSB-SONDERBEH-CD>
    </G-FSB-SONDERBEH-CD>
    <G-FSB-SONDERBEH-CD>
    <G-FSB-SONDERBEH-CD>G-</G-FSB-SONDERBEH-CD>
    </G-FSB-SONDERBEH-CD>
    <G-TFGB-GUT-AN-LB>
    <G-FGB-GGT-ZETT-NR-1>G-FG</G-FGB-GGT-ZETT-NR-1>
    <G-FGB-GGT-ZETT-NR-2>G-FG</G-FGB-GGT-ZETT-NR-2>
    <G-FGB-GGT-ZETT-NR-3>G-FG</G-FGB-GGT-ZETT-NR-3>
    </G-TFGB-GUT-AN-LB>
    <G-TFGB-GUT-AN-LB>
    <G-FGB-GGT-ZETT-NR-1>G-FG</G-FGB-GGT-ZETT-NR-1>
    <G-FGB-GGT-ZETT-NR-2>G-FG</G-FGB-GGT-ZETT-NR-2>
    <G-FGB-GGT-ZETT-NR-3>G-FG</G-FGB-GGT-ZETT-NR-3>
    </G-TFGB-GUT-AN-LB>
    <G-TFGB-GUT-AN-LB>
    <G-FGB-GGT-ZETT-NR-1>G-FG</G-FGB-GGT-ZETT-NR-1>
    <G-FGB-GGT-ZETT-NR-2>G-FG</G-FGB-GGT-ZETT-NR-2>
    <G-FGB-GGT-ZETT-NR-3>G-FG</G-FGB-GGT-ZETT-NR-3>
    </G-TFGB-GUT-AN-LB>
    <G-TFGB-GUT-AN-LB>
    <G-FGB-GGT-ZETT-NR-1>G-FG</G-FGB-GGT-ZETT-NR-1>
    <G-FGB-GGT-ZETT-NR-2>G-FG</G-FGB-GGT-ZETT-NR-2>
    <G-FGB-GGT-ZETT-NR-3>G-FG</G-FGB-GGT-ZETT-NR-3>
    </G-TFGB-GUT-AN-LB>
    <G-FBD-PRIO-KENNZ>G</G-FBD-PRIO-KENNZ>
</G-TFGB-WGN-AN-LB>
<G-TFGB-WGN-AN-LB>
    <G-ZA-WGN-FUNK-CODE>G</G-ZA-WGN-FUNK-CODE>
    <G-FGB-WGN-RIV-CODE>G-</G-FGB-WGN-RIV-CODE>
    <G-FSB-SONDERBEH-CD>
    <G-FSB-SONDERBEH-CD>G-</G-FSB-SONDERBEH-CD>
    </G-FSB-SONDERBEH-CD>
    <G-FSB-SONDERBEH-CD>
    <G-FSB-SONDERBEH-CD>G-</G-FSB-SONDERBEH-CD>
    </G-FSB-SONDERBEH-CD>
    <G-FSB-SONDERBEH-CD>
    <G-FSB-SONDERBEH-CD>G-</G-FSB-SONDERBEH-CD>
    </G-FSB-SONDERBEH-CD>
    <G-FSB-SONDERBEH-CD>
    <G-FSB-SONDERBEH-CD>G-</G-FSB-SONDERBEH-CD>
    </G-FSB-SONDERBEH-CD>
    <G-FSB-SONDERBEH-CD>
    <G-FSB-SONDERBEH-CD>G-</G-FSB-SONDERBEH-CD>
    </G-FSB-SONDERBEH-CD>
    <G-TFGB-GUT-AN-LB>
    <G-FGB-GGT-ZETT-NR-1>G-FG</G-FGB-GGT-ZETT-NR-1>
    <G-FGB-GGT-ZETT-NR-2>G-FG</G-FGB-GGT-ZETT-NR-2>
    <G-FGB-GGT-ZETT-NR-3>G-FG</G-FGB-GGT-ZETT-NR-3>
    </G-TFGB-GUT-AN-LB>
    <G-TFGB-GUT-AN-LB>
    <G-FGB-GGT-ZETT-NR-1>G-FG</G-FGB-GGT-ZETT-NR-1>
    <G-FGB-GGT-ZETT-NR-2>G-FG</G-FGB-GGT-ZETT-NR-2>
    <G-FGB-GGT-ZETT-NR-3>G-FG</G-FGB-GGT-ZETT-NR-3>
    </G-TFGB-GUT-AN-LB>
    <G-TFGB-GUT-AN-LB>
    <G-FGB-GGT-ZETT-NR-1>G-FG</G-FGB-GGT-ZETT-NR-1>
    <G-FGB-GGT-ZETT-NR-2>G-FG</G-FGB-GGT-ZETT-NR-2>
    <G-FGB-GGT-ZETT-NR-3>G-FG</G-FGB-GGT-ZETT-NR-3>
    </G-TFGB-GUT-AN-LB>
    <G-TFGB-GUT-AN-LB>
    <G-FGB-GGT-ZETT-NR-1>G-FG</G-FGB-GGT-ZETT-NR-1>
    <G-FGB-GGT-ZETT-NR-2>G-FG</G-FGB-GGT-ZETT-NR-2>
    <G-FGB-GGT-ZETT-NR-3>G-FG</G-FGB-GGT-ZETT-NR-3>
    </G-TFGB-GUT-AN-LB>
    <G-FBD-PRIO-KENNZ>G</G-FBD-PRIO-KENNZ>
</G-TFGB-WGN-AN-LB>
</NewMessageFormat>

Мой подход состоит в том, чтобы использовать спецификацию формата XML в качестве источника XML, а затем текст передается в качестве строкового параметра в таблицу стилей XLST и использовать встроенный XSLT.Шаблон для обработки каждого узла элемента.Вот моя таблица стилей:

<?xml version="1.0" encoding="UTF-8"?>
<?altova_samplexml file:///D:/Entwicklung/xslt/Test_MFL.xml?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:param name="text"/>
<xsl:template match="/">
    <xsl:apply-templates select="element()"/>
</xsl:template>
<xsl:template name="StructFormat_withoutRepeat" match="StructFormat">
    <xsl:element name="{./@name}">
        <xsl:apply-templates select="element()"/>
    </xsl:element>
</xsl:template>
<xsl:template name="StructFormat" match="StructFormat[@repeat]">
    <xsl:variable name="repeat" select="./@repeat"/>
    <xsl:variable name="Name" select="current()/@name"/>
    <xsl:for-each select="1 to $repeat">
        <xsl:element name="{$Name}">
            <xsl:apply-templates select="element()"/>
        </xsl:element>
        <!--<xsl:call-template name="StructFormat_withoutRepeat"/>-->
    </xsl:for-each>
</xsl:template>
<xsl:template name="FieldFormat" match="FieldFormat">
    <xsl:variable name="fieldName" select="./@name"/>
    <xsl:element name="{./@name}">
        <xsl:value-of select="fn:substring($text,(/MessageFormat//FieldFormat[./@name = $fieldName]/preceding::FieldFormat/@length),  ./@length)"/>
    </xsl:element>
    <xsl:apply-templates select="element()"/>
</xsl:template>
</xsl:stylesheet>

Однако она не работает для повторного strcuture.Проблема в строках:

    <xsl:for-each select="1 to $repeat">
        <xsl:element name="{$Name}">
            <xsl:apply-templates select="element()"/>
        </xsl:element>
        <!--<xsl:call-template name="StructFormat_withoutRepeat"/>-->
    </xsl:for-each>

Может кто-нибудь подсказать, пожалуйста, как решить эту проблему?

Спасибо большое!Dingjun

1 Ответ

0 голосов
/ 15 ноября 2018

Чтобы выбрать дочерние элементы узла контекста за пределами for-each в последовательности чисел, необходимо сохранить его в переменной, например, <xsl:variable name="this" select="."/> перед for-each и затем используйте <xsl:apply-templates select="$this/element()"/> внутри for-each.

Чтобы справиться с повторяющимися элементами, я бы подумал, что двухэтапный подход упрощает эту задачу: на первом этапе (в отдельном режиме) я бы преобразовал каждый struct[@repeat] в соответствующее количество повторяющихся struct элементов, затем Я обработал бы этот результат, и тогда это была бы просто задача вычисления предыдущих длин:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="#all"
    version="3.0">

  <xsl:param name="text" as="xs:string">1234512345123451234512345123451234512345123451234512345</xsl:param>

  <xsl:output method="xml" indent="yes"/>

  <xsl:mode name="unroll" on-no-match="shallow-copy"/>

  <xsl:template match="struct[@repeat]" mode="unroll">
      <xsl:variable name="this" select="."/>
      <xsl:for-each select="1 to @repeat">
          <xsl:copy select="$this">
              <xsl:apply-templates select="@* except @repeat, node()" mode="#current"/>
          </xsl:copy>
      </xsl:for-each>
  </xsl:template>

  <xsl:variable name="complete-struct">
      <xsl:apply-templates mode="unroll"/>
  </xsl:variable>

  <xsl:template match="/">
      <xsl:apply-templates select="$complete-struct/*"/>
  </xsl:template>

  <xsl:template match="struct">
      <xsl:element name="{@name}">
          <xsl:apply-templates/>
      </xsl:element>
  </xsl:template>

  <xsl:template match="field">
      <xsl:element name="{@name}">
          <xsl:value-of select="substring($text, 1 + sum(preceding::field/@length), @length)"/>
      </xsl:element>
  </xsl:template>

</xsl:stylesheet>

Онлайн на https://xsltfiddle.liberty -development.net / eiZQaGj / 4 с XSLT 3 для упрощенной структуры, но также должно быть выполнимо в XSLT: http://xsltransform.hikmatu.com/jyH9rLS, что делает

<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="#all"
    version="2.0">

  <xsl:param name="text" as="xs:string">1234512345123451234512345123451234512345123451234512345</xsl:param>

  <xsl:output method="xml" indent="yes"/>

  <xsl:template match="@*|node()" mode="unroll">
    <xsl:copy>
        <xsl:apply-templates select="@*|node()" mode="#current"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="struct[@repeat]" mode="unroll">
      <xsl:variable name="this" select="."/>
      <xsl:for-each select="1 to @repeat">
          <xsl:element name="{name($this)}" namespace="{namespace-uri($this)}">
              <xsl:apply-templates select="$this/(@* except @repeat, node())" mode="#current"/>
          </xsl:element>
      </xsl:for-each>
  </xsl:template>

  <xsl:variable name="complete-struct">
      <xsl:apply-templates mode="unroll"/>
  </xsl:variable>

  <xsl:template match="/">
      <xsl:apply-templates select="$complete-struct/*"/>
  </xsl:template>

  <xsl:template match="struct">
      <xsl:element name="{@name}">
          <xsl:apply-templates/>
      </xsl:element>
  </xsl:template>

  <xsl:template match="field">
      <xsl:element name="{@name}">
          <xsl:value-of select="substring($text, 1 + sum(preceding::field/@length), @length)"/>
      </xsl:element>
  </xsl:template>

</xsl:transform>

Я не понял и не принял во внимание другие атрибуты, такие как delimOptional, так как я не уверен, что они означают и как их нужно учитывать для правильной позиции для извлечения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...