0

提案どおり。ここで質問 を部分に分けています。

私の入力 xml は、文字列内にフィールドが存在することを示しています。入力 xml には、最大 64 個のフィールド要素を含めることができます。入力 xml フィールド要素は、常に昇順で発生します。私の入力xml

<Root>
  <element>field2</element>
  <element>field3</element>
  <element>field21</element>
</Root>

文字列は、xslt で変数として定義されます。

私の変数

<xsl:variable name="inputstring" select="'013112316145ABC0812345678'"/>

入力xmlは、フィールド2、3、および21が文字列内の唯一のフィールドであり、マッピングxmlに基づいて抽出されることを示しています

ここにマッピングxmlがあります

<Root>
  <field no="2" charlength="2">variable</field>
  <field no="3" total="4">fixed</field>
  <field no="21" charlength="2">
    <subfield no="1" total="3">fixed</subfield>
    <subfield no="2" charlength="2" idcode="ABC">variable</subfield>
  </field>
  <field no="63" charlength="2">
    <format1>
      <subfield no="1" total="3">fixed</subfield>
    </format1>
    <format2>
      <subfield no="1" total="3">fixed</subfield>
      <subfield no="2" total="7">fixed</subfield>
    </format2>
    <format3>
      <subfield no="1" total="3">fixed</subfield>
      <subfield no="2" total="7">fixed</subfield>
      <subfield no="3" total="6">fixed</subfield>
    </format3>
  </field>
</Root>

マッピングxmlは次のことを伝えます

  1. フィールドには、固定、可変、サブフィールドを持つフィールド (固定と可変)、サブフィールドを持つフィールド (異なる形式) の 4 つのタイプがあります。
  2. フィールド番号 2 は可変フィールド (上記のとおり) であり、最初の 2 文字 (charlength 属性) はフィールドの長さを示します。
  3. フィールド 3 は固定で、合計 4 文字です。
  4. フィールド 21 はサブフィールド (固定および可変) を持つフィールドで、最初の 2 つの文字 (charlength) はフィールドの文字数を示します。
    • すべての固定のもの (サブフィールド) が最初に発生し、その後に可変サブフィールドが続きます
    • このサブフィールドは、常に idcode (21 のサブの場合は ABC) で始まり、その後に文字の長さ (charlength 属性)、サブフィールドが続きます。chars の長さは 0 にすることもできます
    • すべての固定フィールドと可変フィールドが出現し、長さ 0 はサブフィールドがないことを示します (ポイントの上)。
  5. フィールド 63 は、フィールドの長さ (charlength 属性) に応じて、サブフィールド (さまざまな形式) を持つフィールドであり、さまざまな形式が可能です。
    • フィールド 63 の場合、長さが 03 (最初の 2 文字、charlength 属性) の場合はフォーマット 1 です。10 の場合はフォーマット 2、16 の場合はフォーマット 3 です。

私の希望する出力xml

<Root>
  <field2>3</field2>
  <!--value is 3 as the charlength is 2(which is 01)-->
  <field3>1123</field3>
  <!--field3 value is 1123 as it is fixed, total length of 4-->
  <field21>
    <subfield1>145</subfield1>
    <!--subfield1 should be 145 as it is fixed length of total 3 chars-->
    <subfield2>12345678</subfield2>
    <!--sufield2 starts with 'ABC', has length 08 chars-->
  </field21>
</Root>

ショーンによる編集。

壊す

これは、入力と出力の間のマッピングの内訳です。

これは、文字列変数 $inputstring の写真です

'013112316145ABC0812345678'

これは、フィールド定義に従って 3 つのフィールドに分割されます...

013    -      1123  -  16145ABC0812345678
 |              |              v  
 v              v           field 21
field2        field3  

フィールド 2 を分解してみましょう。

 01    3
  |    v
  |   payload for field 2. This is output
  v
Contains the length(1) of the payload, which in this case is '01' = 1
This length of this 'header' is given by mapping Root/field[@no="2"]/@charlength
The "2" in this expression comes from the input document node at Root/element .

フィールド 21 を分解します。

16   145   ABC0812345678
 |    |       v
 |    |     subfield 2
 |    \ subfield 1
  \
   v
   Header for field 2. Says that the total field 2 length (header + subfield 1 +
subfield 2 consists of 16 characters. The length for this header was derived from
the mapping node at Root/field[@no="21"]/@charlength .

最後の例: フィールド 21/サブフィールド 2 の内訳。これはサブフィールド 2 の写真です。

ABC   08   12345678
 |     |     |
 |     |     v
 |     |    This is the payload. It is output as the text node child of output
 |     |      subfield 2
 |     v
 v    Length of the following payload
 Signature. The length and value is equal to the mapping node
   Root/field[@no="21"]/subfield[@no="2"]/@idcode
4

1 に答える 1

2

うーん……やらないって言ったけどやった。

注意事項

  1. ルール 5 (多くの形式を持つ複合フィールド) が実装されていませんでした。これは大変な作業だったので、ルール 5 の完成はあなたに任せます。
  2. www.xmlper.com でテストしたので、msxsl:node-set() を使用しました。MS を使用していない場合は、XSLT エンジンに合わせて少し調整する必要があるかもしれません。
  3. これだけ多くの文字列処理を行うと、XSLT 2.0 へのアップグレードを真剣に検討する必要があります。

スタイルシート

この XSLT 1.0 スタイルシート...

<xsl:stylesheet version="1.0"
   exclude-result-prefixes="xsl so msxsl"
   xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
   xmlns:so="http://stackoverflow.com/questions/12035679"
   xmlns:msxsl="urn:schemas-microsoft-com:xslt">
    <xsl:output method="xml" indent="yes" />
    <xsl:strip-space elements="*" />

    <xsl:variable name="inputstring" select="'013112316145ABC0812345678'" />

    <xsl:variable name="map">
        <so:mapping>
            <field no="2" charlength="2">variable</field>
            <field no="3" total="4">fixed</field>
            <field no="21" charlength="2">
                <subfield no="1" total="3">fixed</subfield>
                <subfield no="2" charlength="2" idcode="ABC">variable</subfield>
            </field>
        </so:mapping>
    </xsl:variable>

    <xsl:template match="/*">
        <xsl:copy>
            <xsl:call-template name="process-fields">
                <xsl:with-param name="element-stack" select="element" />
                <xsl:with-param name="code" select="$inputstring" />
            </xsl:call-template>
        </xsl:copy>
    </xsl:template>

    <xsl:template name="process-fields">
        <xsl:param name="element-stack" />
        <xsl:param name="code" />
        <xsl:if test="($code != '') and $element-stack">
            <xsl:variable name="field-no" select="
              substring-after($element-stack[1],'field')" />
            <xsl:variable name="field-parse-request">
                <so:field-parse-request code="{$code}">
                    <xsl:copy-of select="msxsl:node-set($map)/so:mapping/
                       field [@no=$field-no]" />
                </so:field-parse-request>
            </xsl:variable>
            <xsl:variable name="field-parse-result">
                <xsl:apply-templates
                    select="msxsl:node-set($field-parse-request)/*"
                    mode="field-parse" />
            </xsl:variable>
            <xsl:apply-templates
                   select="msxsl:node-set($field-parse-result)/so:output/*"
                   mode="remove-namespaces" />
            <xsl:call-template name="process-fields">
                <xsl:with-param name="element-stack"
                   select="$element-stack[position() &gt; 1]" />
                <xsl:with-param name="code"
                   select="msxsl:node-set($field-parse-result)/
                           so:output[1]/@code" />
            </xsl:call-template>
        </xsl:if>
    </xsl:template>

    <xsl:template match="so:field-parse-request[field[subfield]]"
                     mode="field-parse">
        <so:output>
            <xsl:variable name="header"
                  select="substring(@code,1,field/@charlength)" />
            <xsl:attribute name="code">
                <xsl:value-of
                   select="substring(@code,1+field/@charlength+$header)" />
            </xsl:attribute>
            <xsl:element name="field{field/@no}">
                <xsl:call-template name="process-subfields">
                    <xsl:with-param name="subfield-stack" select="field/subfield" />
                    <xsl:with-param
                      name="code"
                      select="substring(@code,1+field/@charlength,$header)" />
                </xsl:call-template>
            </xsl:element>
        </so:output>
    </xsl:template>

    <xsl:template match="so:field-parse-request[field[.='variable']]"
             mode="field-parse">
        <so:output>
            <xsl:variable name="header"
                   select="substring(@code,1,field/@charlength)" />
            <xsl:attribute name="code">
                <xsl:value-of select="substring(@code,1+field/@charlength+$header)" />
            </xsl:attribute>
            <xsl:element name="field{field/@no}">
                <xsl:value-of select="substring(@code,1+field/@charlength,$header)" />
            </xsl:element>
        </so:output>
    </xsl:template>

    <xsl:template match="so:field-parse-request[subfield[.='variable']]"
            mode="field-parse">
        <so:output>
            <xsl:variable name="header"
               select="substring( @code,
                                  1 + string-length( subfield/@idcode),
                                  subfield/@charlength)" />
            <xsl:attribute name="code">
                <xsl:value-of select="substring(
                     @code,
                     1 + string-length( subfield/@idcode) +
                         subfield/@charlength + $header)" />
            </xsl:attribute>
            <xsl:element name="subfield{subfield/@no}">
                <xsl:value-of select="
                   substring( @code, 
                     1 + string-length( subfield/@idcode) +
                       subfield/@charlength, $header)" />
            </xsl:element>
        </so:output>
    </xsl:template>

    <xsl:template match="so:field-parse-request[ field[.='fixed']] | so:field-parse-request[subfield[.='fixed']]" mode="field-parse">
        <so:output>
            <xsl:attribute name="code">
                <xsl:value-of select="substring(@code, (field/@total | subfield/@total) + 1)" />
            </xsl:attribute>
            <xsl:element name="{concat( name(field|subfield) ,field/@no | subfield/@no)}">
                <xsl:value-of select="substring(@code,1,field/@total | subfield/@total)" />
            </xsl:element>
        </so:output>
    </xsl:template>

    <xsl:template name="process-subfields">
        <xsl:param name="subfield-stack" />
        <xsl:param name="code" />
        <xsl:if test="($code != '') and $subfield-stack">
            <xsl:variable name="active-subfield-index">
                <xsl:choose>
                    <xsl:when test="not( $subfield-stack[1]/@idcode)">1</xsl:when>
                    <xsl:otherwise>
                        <xsl:value-of select="
                           count($subfield-stack
                            [starts-with($code,@idcode)]/preceding-sibling::*)+1" />
                    </xsl:otherwise>
                </xsl:choose>
            </xsl:variable>
            <xsl:variable name="field-parse-request">
                <so:field-parse-request code="{$code}">
                    <xsl:copy-of select="$subfield-stack[$active-subfield-index]" />
                </so:field-parse-request>
            </xsl:variable>
            <xsl:variable name="field-parse-result">
                <xsl:apply-templates
                  select="msxsl:node-set($field-parse-request)/*"
                  mode="field-parse" />
            </xsl:variable>
            <xsl:apply-templates
                select="msxsl:node-set($field-parse-result)/so:output/*"
                mode="remove-namespaces" />
            <xsl:call-template name="process-subfields">
                <xsl:with-param name="subfield-stack"
                  select="$subfield-stack[position() != $active-subfield-index]" />
                <xsl:with-param name="code"
                   select="msxsl:node-set($field-parse-result)/ 
                           so:output[1]/@code" />
            </xsl:call-template>
        </xsl:if>
    </xsl:template>

    <xsl:template match="*" mode="remove-namespaces">
        <xsl:element name="{local-name(.)}">
            <xsl:apply-templates select="@*|node()" mode="remove-namespaces" />
        </xsl:element>
    </xsl:template>

    <xsl:template match="@*|text()" mode="remove-namespaces">
        <xsl:copy />
    </xsl:template>

</xsl:stylesheet>

入力

...この入力ドキュメントを受け取ります...

<Root>
  <element>field2</element>
  <element>field3</element>
  <element>field21</element>
</Root>

出力

...そして、ルール5を除く、すべての規定されたルールに従って変換し、この出力を生成します...

<Root>
  <field2>3</field2>
  <field3>1123</field3>
  <field21>
    <subfield1>145</subfield1>
    <subfield2>12345678</subfield2>
  </field21>
</Root>
于 2012-08-20T17:59:20.927 に答える