5

私は以下のようなフラットな構造のXMLファイルを持っています:

<rs>
    <r id="r1" lev="0"/>
    <r id="r2" lev="1"/>
    <r id="r3" lev="0"/>
    <r id="r4" lev="1"/>
    <r id="r5" lev="2"/>
    <r id="r6" lev="3"/>
    <r id="r7" lev="0"/>
    <r id="r8" lev="1"/>
    <r id="r9" lev="2"/>
</rs>

ネストされたものに変換する必要があります。ルールは何かです。すべてを。r[number(@lev) gt 0]内にネストする必要がありますr[number(@lev) eq 0]。そして、出力は次のようになります。

<rs>
    <r id="r1">
        <r id="r2"/>
    </r>
    <r id="r3">
        <r id="r4">
            <r id="r5">
                <r id="r6"/>
            </r>
        </r>
    </r>
    <r id="r7">
        <r id="r8">
            <r id="r9"/>
        </r>
    </r>
</rs>

私が試したのは、次の変換です。

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

    <xsl:output indent="yes"/>

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

    <xsl:template match="r">
        <xsl:variable name="lev" select="number(@lev)" as="xs:double"/>
        <r>
            <xsl:copy-of select="@id"/>
            <xsl:apply-templates select="following-sibling::r[not(number(@lev) eq $lev)
                                         and 
                                         count(preceding-sibling::r[number(@lev) eq $lev]) eq 1]"/>
        </r>
    </xsl:template>

</xsl:stylesheet>

しかし、これは私に望ましい結果を与えません。私のコーディングエラーや仕事を成し遂げるための他のアプローチを指摘していただければ幸いです。

4

3 に答える 3

3

この変換

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

 <xsl:key name="kRByLevelAndParent" match="r"
  use="concat(generate-id(preceding-sibling::r
                            [not(@lev >= current()/@lev)][1]),
                          @lev
                          )"/>

 <xsl:template match="/*">
  <rs>
    <xsl:apply-templates select="key('kRByLevelAndParent', '0')"/>
  </rs>
 </xsl:template>

 <xsl:template match="r">
  <r id="{@id}">
    <xsl:apply-templates select=
    "key('kRByLevelAndParent',
         concat(generate-id(), @lev+1)
         )"/>
  </r>
 </xsl:template>
</xsl:stylesheet>

提供されたXMLドキュメントに適用した場合:

<rs>
    <r id="r1" lev="0"/>
    <r id="r2" lev="1"/>
    <r id="r3" lev="0"/>
    <r id="r4" lev="1"/>
    <r id="r5" lev="2"/>
    <r id="r6" lev="3"/>
    <r id="r7" lev="0"/>
    <r id="r8" lev="1"/>
    <r id="r9" lev="2"/>
</rs>

必要な正しい結果を生成します。

<rs>
   <r id="r1">
      <r id="r2"/>
   </r>
   <r id="r3">
      <r id="r4">
         <r id="r5">
            <r id="r6"/>
         </r>
      </r>
   </r>
   <r id="r7">
      <r id="r8">
         <r id="r9"/>
      </r>
   </r>
</rs>

説明

複合キーを使用した位置のグループ化-そのすべての「子」について、要素は、そのlev属性がそれぞれのlev属性よりも小さくなるように、最初の先行する兄弟です。

于 2012-06-20T05:32:36.040 に答える
2

Dimitreは、特に要求されない限り、XSLT1.0を使用して質問に回答する傾向があります。これは正しい推測かもしれませんが、XSLT 2.0が非常に広く利用可能になり、使用されていること、およびXSLT 2.0の問題をグループ化するためのコードがはるかに単純であることを指摘する価値があると思います(常にはるかに短いとは限りませんが、はるかに読みやすい)。Dimitreとは異なり、すべての質問に対して美しく完全でテスト済みのソリューションを提供する時間や傾向はありませんが、この問題に対するXSLT 2.0ソリューションを確認したい場合は、数年前にここに書いた論文に1つあります。

http://www.saxonica.com/papers/ideadb-1.1/mhk-paper.xml

再帰テンプレートname="process-level"を検索します。

于 2012-06-20T08:10:14.833 に答える
0

一時変数内で変換を適用する必要があるため、を使用してxsl:keyも役に立ちません。また、 Dimitreのソリューションを使用する必要がある場合は、既存のコードを変更する必要がありました。

そして明らかに、私の質問でこの点についてあまり説明しなかったのは私の間違いでした。

ケイ博士//programlisting[contains(.,'xsl:template name="process-level"')]によって提供されたリンクから、私は解決策を結論付けました、他の誰かが後でそれを使用する可能性があります:

スタイルシート

<xsl:stylesheet version="2.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="xs">
    <xsl:output indent="yes"/>

    <xsl:template match="/*">
        <rs>
            <xsl:call-template name="process-level">
                <xsl:with-param name="context" 
                    select="r"/>
                <xsl:with-param name="level" 
                    select="0"/>
            </xsl:call-template>
        </rs>
    </xsl:template>

    <xsl:template name="process-level">
        <xsl:param name="context" required="yes" as="element()*"/>
        <xsl:param name="level" as="xs:double"/>
        <xsl:for-each-group select="$context"
            group-starting-with="*[number(@lev) eq $level]">
            <xsl:element name="{name()}">
                <!--<xsl:variable name="position" as="xs:double">
                    <xsl:number level="any" count="*[starts-with(local-name(), 'r')]"/>
                </xsl:variable>-->
                <xsl:copy-of select="@id"/>
                <xsl:call-template name="process-level">
                    <xsl:with-param name="context" select="current-group()[position() != 1]"/>
                    <xsl:with-param name="level" select="$level + 1"/>
                </xsl:call-template>
            </xsl:element>
        </xsl:for-each-group>
    </xsl:template>

</xsl:stylesheet>

入力XML

<rs>
    <r id="r1" lev="0"/>
    <r id="r2" lev="1"/>
    <r id="r3" lev="0"/>
    <r id="r4" lev="1"/>
    <r id="r5" lev="2"/>
    <r id="r6" lev="3"/>
    <r id="r7" lev="0"/>
    <r id="r8" lev="1"/>
    <r id="r9" lev="2"/>
</rs>

そしてその結果

<rs>
   <r id="r1">
      <r id="r2"/>
   </r>
   <r id="r3">
      <r id="r4">
         <r id="r5">
            <r id="r6"/>
         </r>
      </r>
   </r>
   <r id="r7">
      <r id="r8">
         <r id="r9"/>
      </r>
   </r>
</rs>
于 2012-06-20T10:24:22.270 に答える