1

XSLT を使用して XML ファイルを変換する必要がありますが、この作業はややこしいものです。

名前の属性がありますがattr_1000_a、番号とサフィックスは動的であるため、それattr_2000_bも有効です。

また、<row>関連するデータを組み合わせる要素もあります。同じ番号の属性 (つまりattr_1000_aattr_1000_b) が同じ要素に配置されるように、それらを変換する必要があります。

例を挙げましょう。次の入力 XML:

<root>
  <row id="1">
    <foo attr_1000_a="true">1</foo>
    <foo attr_1000_b="true">2</foo>
    <foo attr_1000_c="true">3</foo>
  </row>
  <row id="2">
    <foo attr_1000_a="true" attr_1000_b="true" attr_1000_c="true">10</foo>
    <foo attr_2000_a="true" attr_2000_b="true" attr_2000_c="true">20</foo>
  </row>
  <row id="3">
    <foo attr_1000_a="true" attr_2000_a="true" attr_3000_a="true">100</foo>
    <foo attr_1000_b="true" attr_2000_b="true" attr_3000_b="true">200</foo>
    <foo attr_1000_c="true" attr_2000_c="true" attr_3000_c="true">300</foo>
  </row>
</root>

属性をいくつかの方法で組み合わせることができるため、変換が難しくなっていることがわかります。各属性はそれぞれに固有ですが<row>、任意の要素に配置できます <foo>。また、それぞれ<foo>が任意の数の属性を持つことができます。

望ましい結果:

<result>
  <row id="1">
    <field attr="1000">
      <a>1</a>
      <b>2</b>
      <c>3</c>
    </field>
  </row>
  <row id="2">
    <field attr="1000">
      <a>10</a>
      <b>10</b>
      <c>10</c>
    </field>
    <field attr="2000">
      <a>20</a>
      <b>20</b>
      <c>20</c>
    </field>
  </row>
  <row id="3">
    <field attr="1000">
      <a>100</a>
      <b>200</b>
      <c>300</c>
    </field>
    <field attr="2000">
      <a>100</a>
      <b>200</b>
      <c>300</c>
    </field>
    <field attr="3000">
      <a>100</a>
      <b>200</b>
      <c>300</c>
    </field>
  </row>
</result>

行内のすべての数字 (たとえば、1000、2000、3000) のリストを何らかの方法で取得し、そのような属性を持つすべての要素を反復処理する必要があると思います。

XSLTを使用してこれを行うにはどうすればよいですか? これは可能ですか?

4

2 に答える 2

3

サンプルのスタイルシートは次のとおりです。

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:strip-space elements="*"/>
<xsl:output indent="yes"/>

<xsl:key name="k1" 
  match="row/foo/@*" 
  use="concat(generate-id(../..), '|', substring-before(substring-after(local-name(), '_'), '_'))"/>

<xsl:template match="root">
  <result>
    <xsl:apply-templates/>
  </result>
</xsl:template>

<xsl:template match="row">
  <xsl:copy>
    <xsl:copy-of select="@*"/>
    <xsl:apply-templates select="foo/@*[generate-id() = generate-id(key('k1', concat(generate-id(../..), '|', substring-before(substring-after(local-name(), '_'), '_')))[1])]" mode="field"/>
  </xsl:copy>
</xsl:template>

<xsl:template match="foo/@*" mode="field">
  <field attr="{substring-before(substring-after(local-name(), '_'), '_')}">
    <xsl:apply-templates select="key('k1', concat(generate-id(../..), '|', substring-before(substring-after(local-name(), '_'), '_')))"/>
  </field>
</xsl:template>

<xsl:template match="foo/@*">
  <xsl:element name="{substring-after(substring-after(local-name(), '_'), '_')}">
    <xsl:value-of select=".."/>
  </xsl:element>
</xsl:template>

</xsl:stylesheet>
于 2012-06-05T13:41:51.940 に答える
3

クイック アンド ダーティー、この xslt

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">

    <xsl:output indent="yes"/>

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

    <xsl:template match="foo/@*">
        <xsl:element name="{substring-after(local-name(),'000_')}">
            <xsl:value-of select=".."/>
        </xsl:element>
    </xsl:template>

    <xsl:template match="row">
        <row id="{@id}">
            <xsl:for-each-group select="foo/@*" group-by="substring(local-name(),1,9)">
                <field attr="{substring-after(current-grouping-key(),'attr_')}">
                   <xsl:apply-templates select="current-group()"/>
                </field>
            </xsl:for-each-group>
        </row>
    </xsl:template>

    <xsl:template match="foo">
        <xsl:apply-templates  select="@*"/>
    </xsl:template>

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

この入力に適用される

<?xml version="1.0" encoding="UTF-8"?>
<root>
    <row id="1">
        <foo attr_1000_a="true">1</foo>
        <foo attr_1000_b="true">2</foo>
        <foo attr_1000_c="true">3</foo>
    </row>
    <row id="2">
        <foo attr_1000_a="true" attr_1000_b="true" attr_1000_c="true">10</foo>
        <foo attr_2000_a="true" attr_2000_b="true" attr_2000_c="true">20</foo>
    </row>
    <row id="3">
        <foo attr_1000_a="true" attr_2000_a="true" attr_3000_a="true">100</foo>
        <foo attr_1000_b="true" attr_2000_b="true" attr_3000_b="true">200</foo>
        <foo attr_1000_c="true" attr_2000_c="true" attr_3000_c="true">300</foo>
    </row>
</root>

この結果が得られます

<?xml version="1.0" encoding="UTF-8"?>
<result>
    <row id="1">
      <field attr="1000">
         <a>1</a>
         <b>2</b>
         <c>3</c>
      </field>
   </row>
    <row id="2">
      <field attr="1000">
         <a>10</a>
         <b>10</b>
         <c>10</c>
      </field>
      <field attr="2000">
         <a>20</a>
         <b>20</b>
         <c>20</c>
      </field>
   </row>
    <row id="3">
      <field attr="1000">
         <a>100</a>
         <b>200</b>
         <c>300</c>
      </field>
      <field attr="2000">
         <a>100</a>
         <b>200</b>
         <c>300</c>
      </field>
      <field attr="3000">
         <a>100</a>
         <b>200</b>
         <c>300</c>
      </field>
   </row>
</result>

魔法はある

    <xsl:element name="{substring-after(local-name(),'000_')}">
        <xsl:value-of select=".."/>
    </xsl:element>

これにより、動的な名前を持つ a/b/c 要素が作成され、1 つ上のノードに移動して、親ノードから値が取得されます (現在、属性にいます)。

そして

        <xsl:for-each-group select="foo/@*" group-by="substring(local-name(),1,9)">
            <field attr="{substring-after(current-grouping-key(),'attr_')}">
               <xsl:apply-templates select="current-group()"/>
            </field>
        </xsl:for-each-group>

名前foo/@*一部 ( ) を使用して、すべての属性 ( ) を再グループ化します。ご覧のとおり、前者は として、後者は として引き続き利用できます。 substring(local-name(),1,9)current-group()current-grouping-key()

于 2012-06-05T13:56:38.237 に答える