2016-11-24 5 views
0

言って名前を属性。しかし、学習目的のために、 "id"という属性の値をXSLTで変更する方法を知りたいと思います。私のような「アルゴリズム」について考えてきました避け、私はそのようなXMLを持っているXSLT/XPathの

は、以下の属性の前の兄弟を検討してください。
現在の属性の重複を満たす場合は、同じ名前の属性がなくなるまで、この名前の末尾に "f"を追加し、別の "f"を(再帰的に)追加します。

だから私の最後のXMLは次のように次のようになります。今

<parole> 
    <parola id="a">1</parola> 
    <parola id="b">2</parola> 
    <parola id="c">3</parola> 
    <parola id="af">4</parola> 
    <parola id="aff">5</parola> 
    <parola id="bf">6</parola> 
</parole> 

、私のような再帰関数で、この結果を得るために試してみた:

<xsl:variable name="following-siblings-ids" select="/parole/parola/following-sibling::parola/@id"/> 
<xsl:variable name="preceding-siblings-ids" select="/parole/parola/preceding-sibling::parola/@id"/> 

<xsl:function name="du:check" as="xs:string"> 
    <xsl:param name="id" /> 
    <xsl:choose> 
     <xsl:when test="$id = $following-siblings-ids and $preceding-siblings-ids"> 
      <xsl:value-of select="du:check(concat($id, 'f'))"/> 
     </xsl:when> 
     <xsl:otherwise> 
      <xsl:value-of select="$id"/> 
     </xsl:otherwise> 
    </xsl:choose> 
</xsl:function> 

<xsl:template match="parola"> 
    <xsl:value-of select="du:check(@id)"/> 
</xsl:template match="parola"> 

しかし、私は次のような結果を得ます

"AF" "BF" "CF" "AF" "AF" "BF"

所望のものの代わりに10

である。

ヒントこれは、動的変数とfor-eachの非宣言言語の単純なタスクですが、私はXSLTでそれを実現する方法がわかりません...

+0

はあなたのサンプル文書の最初の行は、ID * A *の代わりに、* AF *を持っていないでしょうか? – Markus

+0

あなたはおそらく前の@ idを現在のものと同じものに数え、最後にfを追加するべきです。おそらくヒットしていないポイントは、「(再帰的に)別のfを追加する」という場所です。これは、前の繰り返しの結果に対して* n *回実行する必要があることを意味します(ただし、 ) –

+0

はい、修正済み、@マークス – AmintaCode

答えて

1

ここはXSLT 1ソリューションです。次の変換

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

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

    <xsl:template name="make-f"> 
    <xsl:param name="n"/> 
    <xsl:if test="$n > 0">f<xsl:call-template name="make-f"> 
    <xsl:with-param name="n" select="$n - 1"/></xsl:call-template> 
    </xsl:if> 
    </xsl:template> 

    <xsl:template match="parola/@id"> 
    <xsl:variable name="id" select="."/> 
    <xsl:variable name="f"> 
     <xsl:call-template name="make-f"> 
    <xsl:with-param name="n" select="count(../preceding-sibling::parola/@id[.=$id])"/> 
     </xsl:call-template> 
    </xsl:variable> 
    <xsl:attribute name="id"> 
     <xsl:value-of select="concat(., $f)"/> 
    </xsl:attribute> 
    </xsl:template> 

</xsl:stylesheet> 

ご入力サンプルに適用され、次の出力を生成します。

$ xsltproc test.xsl test.xml 
<?xml version="1.0"?> 
<parole> 
    <parola id="a">1</parola> 
    <parola id="b">2</parola> 
    <parola id="c">3</parola> 
    <parola id="af">4</parola> 
    <parola id="aff">5</parola> 
    <parola id="bf">6</parola> 
</parole> 
0

私はキーを使用して要素を「グループ化」します。その後、id属性やインデックスを追加し、そのグループ内の位置を特定したりしたい場合はf文字の数:

<?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" 
    xmlns:mf="http://example.com/mf" 
    exclude-result-prefixes="xs mf" 
    version="2.0"> 

    <xsl:param name="n" select="'f'"/> 

    <xsl:function name="mf:node-index-of" as="xs:integer"> 
     <xsl:param name="node" as="node()"/> 
     <xsl:param name="sequence" as="node()*"/> 
     <xsl:sequence select="for $pos in 1 to count($sequence) return $pos[$node is $sequence[$pos]]"/> 
    </xsl:function> 

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

    <xsl:key name="p-by-id" match="parola" use="@id"/> 

    <xsl:template match="parola[not(. is key('p-by-id', @id)[1])]/@id"> 
     <xsl:attribute name="id" select="concat(., string-join(for $i in 1 to mf:node-index-of(.., key('p-by-id', .)) - 1 return $n, ''))"/> 
    </xsl:template> 

</xsl:stylesheet> 

テンプレートmatch="@* | node()"とはレベルによってコピーのすべてを変更しないレベル、いわゆる恒等変換テンプレートです変換したいノードのテンプレートを追加することができます。

あなたが変換したいだけのノードが2つ以上が特定のid値で存在するparola要素のid属性であるので、私は同じで、すべての要素を識別するためのキー<xsl:key name="p-by-id" match="parola" use="@id"/>を使用して、そのためのテンプレートmatch="parola[not(. is key('p-by-id', @id)[1])]/@id"を書かれています値。

新しい属性値concat(., string-join(for $i in 1 to mf:node-index-of(.., key('p-by-id', .)) - 1 return $n, ''))は、$nを含むシーケンスで既存の値を連結し、そのグループ内の親の位置インデックスの回数を減じて計算されます。

XSLTとXPath 2.0を初めてお使いの方は、チュートリアルやアイデンティティの変換、キー、およびユーザー定義関数についての書籍を読んでください。

+0

あなたの解決策を少しずつ説明できますか?私は非常に感謝しています@マーティン・ホーネン – AmintaCode

関連する問題