1

Web から派生した XML を変換するために XSLT を使用しており、その場で同じものを output として示されるターゲット xml ファイルに変換します。いろいろ試してもまだできません。誰かこの変換を手伝ってくれませんか。

ソース XML

<allocelement>
    <hd1>12</hd1>
    <hd2>14</hd2>
    <hd3>87</hd3>
        <alc>1</alc>
    <amount>4587</amount>
    <code>1111</code>
</allocelement>
<alloclement>
        <hd1>12</hd1>
    <hd2>14</hd2>
    <hd3>87</hd3>
    <alc>2</alc>
    <amount>80000</amount>
    <code>1111</code>
</alloclement>
<alloclement>
    <hd1>875</hd1>
    <hd2>455</hd2>
    <hd3>455</hd3>
    <alc>2</alc>
    <amount>80000</amount>
    <code>1112</code>
 </alloclement>

出力希望

<allocelement>
    <Codeheader>
    <code>1111</code>
        <hd1>12</hd1>
        <hd2>14</hd2>
        <hd3>87</hd3>
                <alc>1</alc>
                    <amount>4587</amount>
                <alc>2</alc>
                    <amount>80000</amount>
    </codeHeader>
        <CodeHeader>
    <code>1112</code>
        <hd1>875</hd1>
        <hd2>455</hd2>
        <hd3>455</hd3>
            <alc>2</alc>
              <amount>80000</amount>
    </CodeHeader>
</allocelement>

グループ化はコード [hd1,hd2,hd3] に基づいており、同じコードと [hd1,hd2,hd3] を持つさまざまな要素がマージされ、異なるフィールドのみが表示されます。と . また、 xslt 1.0 を使用しています。

4

2 に答える 2

0

大幅に短くシンプルなXSLT1.0ソリューション

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:key name="kCodeByVal" match="code" use="."/>

 <xsl:template match="/*">
  <allocelement>
   <xsl:apply-templates/>
  </allocelement>
 </xsl:template>

<xsl:template match="allocelement"/>

 <xsl:template match=
  "allocelement
    [generate-id(code) = generate-id(key('kCodeByVal', code)[1])]">
  <code><xsl:value-of select="code"/>
    <xsl:copy-of select=
    "node()[not(self::code)]
    | key('kCodeByVal', code)/../*[self::alc or self::amount]"/>
  </code>
 </xsl:template>
</xsl:stylesheet>

この変換が次のXMLドキュメント(提供されたXMLフラグメントをラップする単一の最上位要素)に適用される場合:

<t>
    <allocelement>
        <hd1>12</hd1>
        <hd2>14</hd2>
        <hd3>87</hd3>
        <alc>1</alc>
        <amount>4587</amount>
        <code>1111</code>
    </allocelement>
    <allocelement>
        <hd1>12</hd1>
        <hd2>14</hd2>
        <hd3>87</hd3>
        <alc>2</alc>
        <amount>80000</amount>
        <code>1111</code>
    </allocelement>
    <allocelement>
        <hd1>875</hd1>
        <hd2>455</hd2>
        <hd3>455</hd3>
        <alc>2</alc>
        <amount>80000</amount>
        <code>1112</code>
    </allocelement>
</t>

必要な正しい結果が生成されます:

<allocelement>
   <code>1111<hd1>12</hd1>
      <hd2>14</hd2>
      <hd3>87</hd3>
      <alc>1</alc>
      <amount>4587</amount>
      <alc>2</alc>
      <amount>80000</amount>
   </code>
   <code>1112<hd1>875</hd1>
      <hd2>455</hd2>
      <hd3>455</hd3>
      <alc>2</alc>
      <amount>80000</amount>
   </code>
</allocelement>

説明ミュンヒアングループ化法の適切な使用。


II。XSLT 2.0ソリューション-これも短く、さらに重要なことに-構文的および意味的に正しい

<xsl:stylesheet version="2.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

  <xsl:template match="/*">
  <allocelement>
   <xsl:for-each-group select="*" group-by="code">
     <code><xsl:value-of select="code"/>
        <xsl:sequence select=
        "node()[not(self::code)]
        | current-group()/*[self::alc or self::amount]"/>
  </code>
   </xsl:for-each-group>
  </allocelement>
 </xsl:template>
</xsl:stylesheet>

更新:OPはoutpuの要件を変更しました。

対応する変更されたXSLT1.0ソリューションは次のとおりです。

<xsl:stylesheet version="1.0"
     xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
     <xsl:output omit-xml-declaration="yes" indent="yes"/>
     <xsl:strip-space elements="*"/>

     <xsl:key name="kCodeByVal" match="code" use="."/>

     <xsl:template match="/*">
      <allocelement>
       <xsl:apply-templates/>
      </allocelement>
     </xsl:template>

    <xsl:template match="allocelement"/>

     <xsl:template match=
      "allocelement
        [generate-id(code) = generate-id(key('kCodeByVal', code)[1])]">
      <codeHeader>
       <code><xsl:value-of select="code"/></code>
         <xsl:copy-of select=
         "node()[not(self::code)]
         | key('kCodeByVal', code)/../*[self::alc or self::amount]"/>
      </codeHeader>
     </xsl:template>
</xsl:stylesheet>
于 2012-05-30T04:05:54.573 に答える
0

入力 XML には、整形式のrootドキュメントを作成するためにすべてをラップするノードがあると思います。また、すべてが正しいスペルであると仮定しallocelementます(一部のスペルは ですalloclement)。また、タグ名とそのテキスト値によって識別される重複を削除したいと考えています。

XSLT 1.0の場合:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output omit-xml-declaration="yes" indent="yes"/>
    <xsl:strip-space elements="*"/>

    <xsl:key name="code" match="allocelement/code" use="."/>

    <xsl:key name="code-sibling" 
             match="allocelement/*[name() != 'code']" 
             use="concat(parent::*/code, '|', name(), '|', .)"/>

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

    <xsl:template match="/">
        <xsl:apply-templates select="root/allocelement[1]"/>
    </xsl:template>

    <xsl:template match="allocelement">
        <xsl:copy>
            <xsl:apply-templates select="@*"/>
            <xsl:apply-templates 
                    select="(. | following-sibling::allocelement)/code
                                [generate-id() = generate-id(key('code', .)[1])]"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="code">
        <xsl:copy>
            <xsl:apply-templates select="@*"/>
            <xsl:value-of select="."/>

            <xsl:apply-templates 
                    select="key('code', .)/(preceding-sibling::* | following-sibling::*)
                                [generate-id() = 
                                 generate-id(key('code-sibling', concat(parent::*/code, '|', name(), '|', .))[1])]"/>
        </xsl:copy>
    </xsl:template>

</xsl:stylesheet>

適用時:

<root>
    <allocelement>
        <hd1>12</hd1>
        <hd2>14</hd2>
        <hd3>87</hd3>
        <alc>1</alc>
        <amount>4587</amount>
        <code>1111</code>
    </allocelement>
    <allocelement>
        <hd1>12</hd1>
        <hd2>14</hd2>
        <hd3>87</hd3>
        <alc>2</alc>
        <amount>80000</amount>
        <code>1111</code>
    </allocelement>
    <allocelement>
        <hd1>875</hd1>
        <hd2>455</hd2>
        <hd3>455</hd3>
        <alc>2</alc>
        <amount>80000</amount>
        <code>1112</code>
     </allocelement>
</root>

生成:

<root>
   <allocelement>
      <code>1111<hd1>12</hd1>
         <hd2>14</hd2>
         <hd3>87</hd3>
         <alc>1</alc>
         <amount>4587</amount>
         <alc>2</alc>
         <amount>80000</amount>
      </code>
      <code>1112<hd1>875</hd1>
         <hd2>455</hd2>
         <hd3>455</hd3>
         <alc>2</alc>
         <amount>80000</amount>
      </code>
   </allocelement>
</root>

仕組みは次のとおりです。デフォルト ルートは恒等変換です。最初に中断しallocelement、変換を別のルートに送ります。一意の要素 (要素のテキスト値によって識別される一意性) をその値とともにコピーし、同じ値を共有するすべてのノードcodeの前後のすべての兄弟にテンプレートを適用します。codeこれらは、code現在のノードの子ノードになります。次に、一意の兄弟 (同じ値の に属し、code同じ名前と同じテキスト値を持つ) の恒等変換を呼び出します。

1 つのメモ。MIXED コンテンツは決して良い考えではありません。の下にテキスト値と子ノードを混在させる必要があるかどうかを確認してくださいcode

XSLT 2.0を使用すると、 generate-id()sを避けることができます。

<xsl:template match="allocelement">
    <xsl:copy>
        <xsl:apply-templates select="@*"/>
        <xsl:for-each-group select="(. | following-sibling::allocelement)/code" group-by=".">
            <xsl:apply-templates select="."/>
        </xsl:for-each-group>
    </xsl:copy>
</xsl:template>

<xsl:template match="code">
    <xsl:copy>
        <xsl:apply-templates select="@*"/>
        <xsl:value-of select="."/>

        <xsl:for-each-group select="key('code', .)/(preceding-sibling::* | following-sibling::*)"
                            group-by="concat(parent::*/code, '|', name(), '|', .)">
            <xsl:apply-templates select="."/>
        </xsl:for-each-group> 
    </xsl:copy>
</xsl:template>
于 2012-05-29T14:14:07.867 に答える