0

次のようなサンプルの xml 入力があります。

<table name="Table1">
<fields>
   <field name="Field1" />
   <field name="Field2" />
   <field name="Field3" />
   <field name="Field4" />
</fields>
<data>
   <row value="2,Description1,A,AA" />
   <row value="3,Description2,B,BB" />
   <row value="7,Description3,C,CC" />
</data>
</table>
<table name="Table2">
<fields>
   <field name="Field7" />
   <field name="Field8" />
   <field name="Field9" />
</fields>
<data>
   <row value="Q,Description7,A" />
   <row value="W,Description8,B" />
   <row value="X,Description9,C" />
</data>
</table>

フィールドの数が異なる多くのテーブルを持つことができますが、行の値には常に必要なフィールドの正確な数が含まれていることに注意してください。

期待される結果は、次のような出力です。

<ListOfTable1>
<item>
   <Field1>2</Field1>
   <Field2>Description1</Field2>
   <Field3>A</Field3>
   <Field4>AA</Field4>
</item>
<item>
   <Field1>3</Field1>
   <Field2>Description2</Field2>
   <Field3>B</Field3>
   <Field4>BB</Field4>
</item>
<item>
   <Field1>7</Field1>
   <Field2>Description3</Field2>
   <Field3>C</Field3>
   <Field4>CC</Field4>
</item>
</ListOfTable1>

<ListOfTable2>
<item>
   <Field7>Q</Field7>
   <Field8>Description7</Field8>
   <Field9>A</Field9>
</item>
<item>
   <Field7>W</Field7>
   <Field8>Description8</Field8>
   <Field9>B</Field9>
</item>
<item>
   <Field7>X</Field7>
   <Field8>Description9</Field8>
   <Field9>C</Field9>
</item>
</ListOfTable2>

残念ながら厳密な XSLT 1.0 しか使用できません 外部関数や参照はありません

提案された3番目のソリューションのわずかに変更されたバージョンを使用しています

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

  <xsl:template match="//table">
    <xsl:value-of disable-output-escaping="yes" select="concat('&lt;ListOf',@name,'&gt;')" />
    <xsl:apply-templates />
    <xsl:value-of disable-output-escaping="yes" select="concat('&lt;/ListOf',@name,'&gt;')" />
  </xsl:template>

  <xsl:template match="table/data/row">
    <item>
      <xsl:call-template name="fldsplit">
        <xsl:with-param name="f" select="@value" />
        <xsl:with-param name="set" select="//fields/field" />
      </xsl:call-template>
    </item>
  </xsl:template>

  <xsl:template name="fldsplit">
    <xsl:param name="f" />
    <xsl:param name="set"/>
    <xsl:variable name="bfc" select="substring-before($f,',')"/>
    <xsl:variable name="afc" select="substring-after($f,',')"/>
    <xsl:element name="{$set/@name}">
      <xsl:choose>
        <xsl:when test="$bfc">
          <xsl:value-of select="$bfc"/>
        </xsl:when>
        <xsl:otherwise>
          <xsl:value-of select="$f"/>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:element>
    <xsl:if test="$afc">
      <xsl:call-template name="fldsplit">
        <xsl:with-param name="f" select="$afc"/>
        <xsl:with-param name="set" select="$set/following-sibling::*" />
      </xsl:call-template>
    </xsl:if>
  </xsl:template>

</xsl:stylesheet>

しかし、2 番目のテーブル (または入力に追加するその他のテーブル) に問題があります。つまり、フィールド名は常に Field1 から始まり、解析される各テーブルに特定のフィールドを使用することを期待しています。

これは現在の出力です(間違っています)

<?xml version="1.0" encoding="UTF-8"?>

<ListOfTable1>
   <item><Field1>2</Field1><Field2>Description1</Field2><Field3>A</Field3><Field4>AA</Field4></item>
   <item><Field1>3</Field1><Field2>Descritpion2</Field2><Field3>B</Field3><Field4>BB</Field4></item>
   <item><Field1>7</Field1><Field2>Description3</Field2><Field3>C</Field3><Field4>CC</Field4></item>
</ListOfTable1>
<ListOfTable2>
   <item><Field1>Q</Field1><Field2>Description7</Field2><Field3>A</Field3></item>
   <item><Field1>W</Field1><Field2>Description8</Field2><Field3>B</Field3></item>
   <item><Field1>X</Field1><Field2>Description9</Field2><Field3>C</Field3></item>
</ListOfTable2>
4

3 に答える 3

1

まあ、これは期待どおりに動作するはずです:

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

<xsl:template match="row">
    <xsl:variable name="field1" select="substring-before(@value,',')"/>
    <xsl:variable name="field2" select="substring-after(@value,',')"/>
    <item>
       <Field1><xsl:value-of select="$field1"/></Field1>
       <Field2><xsl:value-of select="$field2"/></Field2>
    </item>
</xsl:template>

ご覧のとおり、私はあなたの部分を使用しませんでした (ところで、Field2 の type="int" はサンプルに適合しないようです)。それはフィールドの数であるべきですか?(定義されていない数のフィールドが存在する可能性がある場合は、再帰的な解決策が必要になります...)


編集 :

OK、私は任意の数のフィールドで動作するソリューションを書くことができました:

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

<xsl:key name="allfields" match="field" use="count(preceding-sibling::field) + 1"/>

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

<xsl:template match="row">
    <item>
    <xsl:call-template name="row">
        <xsl:with-param name="value" select="@value"/>
        <xsl:with-param name="pos" select="1"/>
    </xsl:call-template>
    </item>
</xsl:template>

<xsl:template name="row">
    <xsl:param name="value"/>
    <xsl:param name="pos"/>
    <xsl:variable name="field1">
        <xsl:choose>
            <xsl:when test="contains($value,',')">
                <xsl:value-of select="substring-before($value,',')"/>
            </xsl:when>
            <xsl:otherwise>
                <xsl:value-of select="$value"/>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:variable>
    <xsl:variable name="fieldNext" select="substring-after($value,',')"/>
    <xsl:variable name="fieldName" select="key('allfields',$pos)/@name"/>
        <xsl:element name="{$fieldName}">
            <xsl:value-of select="$field1"/>
        </xsl:element>
        <xsl:if test="not($fieldNext='')">
            <xsl:call-template name="row">
                <xsl:with-param name="value" select="$fieldNext"/>
                <xsl:with-param name="pos" select="$pos + 1"/>
            </xsl:call-template>
        </xsl:if>
</xsl:template>
</xsl:stylesheet>

これは、XSLT1.0がそのようなものに非常に適していないことを示しています...

于 2013-10-07T15:41:15.043 に答える
0

で区切られた対応する数のフィールドがあると仮定して、複数のフィールドを処理できるソリューションを次に示します。

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

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


  <xsl:template match="data/row">
    <item>
      <xsl:call-template name="fldsplit">
        <xsl:with-param name="f" select="@value" />
        <xsl:with-param name="set" select="//fields/field" />
      </xsl:call-template>
    </item>
  </xsl:template>

  <xsl:template name="fldsplit">
    <xsl:param name="f" />
    <xsl:param name="set"/>
    <xsl:variable name="bfc" select="substring-before($f,',')"/>
    <xsl:variable name="afc" select="substring-after($f,',')"/>
    <xsl:element name="{$set/@name}">
      <xsl:choose>
        <xsl:when test="$bfc">
          <xsl:value-of select="$bfc"/>
        </xsl:when>
        <xsl:otherwise>
          <xsl:value-of select="$f"/>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:element>
    <xsl:if test="$afc">
      <xsl:call-template name="fldsplit">
        <xsl:with-param name="f" select="$afc"/>
        <xsl:with-param name="set" select="$set/following-sibling::*" />
      </xsl:call-template>
    </xsl:if>
  </xsl:template>
于 2013-10-07T16:04:08.547 に答える