価値のあることとして、XSLT 1.0 でこれを行う方法を次に示します。
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes" />
<xsl:strip-space elements="*" />
<xsl:key name="name" match="*[@name]" use="
concat(@name, '|', ancestor::*[1]/@name, '|', ancestor::*[2]/@name)
" />
<xsl:template match="node() | @*">
<xsl:copy>
<xsl:apply-templates select="node() | @*" />
</xsl:copy>
</xsl:template>
<xsl:template match="*[@name]">
<xsl:variable name="myKey" select="
concat(@name, '|', ancestor::*[1]/@name, '|', ancestor::*[2]/@name)
" />
<xsl:variable name="myGroup" select="key('name', $myKey)" />
<xsl:if test="generate-id() = generate-id($myGroup[1])">
<xsl:copy>
<xsl:copy-of select="@*" />
<xsl:apply-templates select="$myGroup/*" />
</xsl:copy>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
出力
<roots>
<root name="name1">
<layer1 name="name2">
<layer2 attribute="sowhat"/>
<layer2 attribute="justit"/>
<layer2 attribute="yeaha"/>
</layer1>
</root>
<root name="name2123">
<layer1 name="name2">
<layer2 attribute="itis"/>
</layer1>
</root>
</roots>
XSLT の重要な機能は、比較的少ないコード行で複雑な変換を表現できることです。上記の変換は 29 行のコードであり、さらに絞り込むことができます。
XSLT の短期集中コースは、この回答の範囲を超えていると思います。それに加えて、XSLT のクラッシュ コースはインターネット上で無数にあります。
そこで私がやっていることは、ここで何が起こっているかの一般的な概要を説明することです。
まず、入力用に要素の 2 つのクラスを定義しました。マージ可能なものとそうでないものです。@name
属性を持つすべての要素をマージ可能に定義しました。
- 通常のノード ( のないもの
@name
) はすべてそのままコピーされます。最初の<xsl:template>
ものはそれを行います (これはID テンプレートです)。
@name
先祖に沿って属性値
の共通セットを共有する要素として、要素の「マージ可能なグループ」を定義しました。
@name
そのために、関連するすべての属性を持つすべての要素の連結を作成します。
- 当分の間、この変換は 3 レベルの深さのグループを処理できます (
concat(@name, '|', ancestor::*[1]/@name, '|', ancestor::*[2]/@name)
)。
- 必要に応じて、同じ方法でさらにレベルを追加します。
- の親のグループ名 (キー
sowhat
) は です。これは、その論理グループname2|name1||
の他のグループに適用されます。<layer2>
- XSLT エンジンが を含む要素に遭遇するたびに
@name
、
- その要素のキーを計算します(
$myKey
)。
- 同じキー ( ) を持つ要素のグループを取得します
$myGroup
。
- 現在の要素がグループ内の最初の要素かどうかを調べ、そうであれば出力にコピーします
- 事実上、これはキーによって要素をグループ化します (この手法はMuenchian グループ化と呼ばれます)。
- 次に、再帰的な手順を実行します。そのグループの子の処理を開始します (
$myGroup/*
)。
- 事実上、これにより正方形 0 に戻り、アルゴリズムが最初から開始されます。
私のコードには、必ずしも入力と一致しない可能性のあるいくつかの仮定/制限があります。
@name
要素は、他のプロパティではなく、要素によってマージされるべきです。
- 同じ
@name
祖先を持つ要素には特別な属性がないため、特定のグループの最初の要素を除いてすべての要素を破棄しても、データが失われることはありません。
- 入れ子の深さは有限です。
- マージ可能な要素は、マージ不可能な要素の子孫になることはありません (内に a が
<layer>
なくても)@name
<layer>
@name
- おそらく、今私の心をすり抜ける他の人たち。
読書のおすすめ
- テンプレート マッチングと XSLT プロセッサの一般的な動作メカニズム
- XSL のデフォルト ルール
- XPath
- XSL キーと Muenchian グループ化
- ID テンプレート
- 処理フロー全体の現在のノードの概念