1

次のようなxmlドキュメントがあります。

<Catalogs>
    <Catalog>
        <Code>x</Code>
        <Name>Ox</Name>
        <Categories>
            <Category>
                <Id>9245</Id>
                <Name>a</Name>
                <Category>
                    <Id>9247</Id>
                    <Name>x</Name>
                </Category>
            </Category>
            <Category>
                <Id>9250</Id>
                <Name>x</Name>
                <Category>
                    <Id>9252</Id>
                    <Name>x</Name>
                </Category>
                <Category>
                    <Id>9258</Id>
                    <Name>x</Name>
                    <Category>
                        <Id>9260</Id>
                        <Name>x</Name>
                    </Category>
                    <Category>
                        <Id>9261</Id>
                        <Name>x</Name>
                    </Category>
                    <Category>
                        <Id>9261</Id>
                        <Name>x</Name>
                    </Category>
                </Category>
            </Category>
            <Category>
                <Id>9251</Id>
                <Name>x</Name>
                <Category>
                    <Id>9253</Id>
                    <Name>x</Name>
                </Category>
            </Category>
        </Categories>
    </Catalog>
</Catalogs>

カテゴリ タグの各サブセットをコレクション タグ (カテゴリ) にラップしたいと思います。ここでの問題は、これが再帰ツリーであり、ツリーの深さが不明であることです。

これに xslt 変換を使用しようとしましたが、まだ成功していません。私の試み

<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:template match="Category">
  <Categories><xsl:apply-templates select="Category"/></Categories>
</xsl:template>

</xsl:stylesheet>

すべての子を空の Categories タグに置き換えるだけです。

サンプル出力は次のようになります。

<Catalogs>
    <Catalog>
        <Code>x</Code>
        <Name>Ox</Name>
        <Categories>
            <Category>
                <Id>9245</Id>
                <Name>a</Name>
                <Categories>
                    <Category>
                        <Id>9247</Id>
                        <Name>x</Name>
                    </Category>
                </Categories>
            </Category>
            <Category>
                <Id>9250</Id>
                <Name>x</Name>
                <Categories>
                    <Category>
                        <Id>9252</Id>
                        <Name>x</Name>
                    </Category>
                    <Category>
                        <Id>9258</Id>
                        <Name>x</Name>
                        <Categories>
                            <Category>
                                <Id>9260</Id>
                                <Name>x</Name>
                            </Category>
                            <Category>
                                <Id>9261</Id>
                                <Name>x</Name>
                            </Category>
                            <Category>
                                <Id>9261</Id>
                                <Name>x</Name>
                            </Category>
                        </Categories>
                    </Category>
                </Categories>
            </Category>
            <Category>
                <Id>9251</Id>
                <Name>x</Name>
                <Categories>
                    <Category>
                        <Id>9253</Id>
                        <Name>x</Name>
                    </Category>
                </Categories>
            </Category>
        </Categories>
    </Catalog>
</Catalogs>

任意のポインタ(または完全なソリューション)をいただければ幸いです。

4

1 に答える 1

4

まず、XSLT ID テンプレートの上に XSLT を構築する必要があります。これにより、明示的に一致するテンプレートがない XML 内のすべてのノードがコピーされます。

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

これがないと、XSLT の組み込みテンプレートが起動し、見つかった要素のテキストを出力するだけになります。

XSLT のもう 1 つの問題は、 Category要素を照合するときに、 XSLT に現在の要素の子であるCategory要素<xsl:apply-templates select="Category"/>を探すように指示しているだけだということです。

あなたが取ることができる1つのアプローチは、テンプレートを任意のCategory要素の親と一致させることです(すでにCategories要素を除く)

<xsl:template match="*[not(self::Categories)][Category]">

次に、この中に要素をコピーし、その中にCategories要素を挿入して、すべてのCategory要素を含めることができます。

<xsl:copy>
  <xsl:apply-templates select="@*|node()[not(self::Category)]"/>
  <Categories>
    <xsl:apply-templates select="Category"/>
  </Categories>
</xsl:copy>

この場合の完全な XSLT は次のとおりです。

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" indent="yes"/>

  <xsl:template match="*[not(self::Categories)][Category]">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()[not(self::Category)]"/>
      <Categories>
        <xsl:apply-templates select="Category"/>
      </Categories>
    </xsl:copy>
  </xsl:template>

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

ただし、このアプローチの欠点は、親内のカテゴリの後に発生する要素がある場合、作成されるカテゴリ要素の前に移動されることです。

別のアプローチは、親内のCategory要素の最初の出現に一致し、その要素とそれに続くすべての兄弟をコピーすることです

このXSLTも試してみてください

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" indent="yes"/>

  <xsl:template match="Category[1]">
    <Categories>
      <xsl:apply-templates select="self::*|following-sibling::Category" mode="categories"/>
    </Categories>
  </xsl:template>

  <xsl:template match="Category" mode="categories">
    <xsl:call-template name="identity" />
  </xsl:template>

  <xsl:template match="Category" />

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

このアプローチについて注意すべき点が 2 つあります。まず、XSLT は、ノードに一致するテンプレートを探すときに、より具体的なテンプレートの一致を常に優先します。したがって、「Category[1]」は、最初の子カテゴリ要素の「Category」よりも使用されます。

次に、ここでのモードの使用に注意してください。そうしないと、「Category」に一致する同じ優先度を持つ 2 つのテンプレートができてしまい、許可されません。

于 2013-07-31T12:21:23.497 に答える