0

I have the following structure in an XML-file:

<root name="name1">
  <layer1 name="name2">
    <layer2 attribute="sowhat">
    </layer2>
  </layer1>
</root>
<root name="name1">
  <layer1 name="name2">
    <layer2 attribute="justit">
    </layer2>
  </layer1>
</root>
<root name="name1">
  <layer1 name="name2">
    <layer2 attribute="yeaha">
    </layer2>
  </layer1>
</root>
<root name="name2123">
  <layer1 name="name2">
    <layer2 attribute="itis">
    </layer2>
  </layer1>
</root>

And I want to get a result that looks like:

<root name="name1">
  <layer1 name="name2">
    <layer2 attribute="sowhat"></layer2>
    <layer2 attribute="justit"></layer2>
    <layer2 attribute="yeaha"></layer2>
  </layer1>
</root>
<root name="name2123">
  <layer1 name="name2">
    <layer2 attribute="itis">
    </layer2>
  </layer1>
</root>

So I want to merge and combine nodes as far as possible. I havent uses XSLT yet, tried it, but I dont get it, not even the general idea. Any other ideas or tools?

Thanks

4

1 に答える 1

2

価値のあることとして、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属性を持つすべての要素をマージ可能に定義しました。

  1. 通常のノード ( のないもの@name) はすべてそのままコピーされます。最初の<xsl:template>ものはそれを行います (これはID テンプレートです)。
  2. @name先祖に沿って属性値 の共通セットを共有する要素として、要素の「マージ可能なグループ」を定義しました。
    • @nameそのために、関連するすべての属性を持つすべての要素の連結を作成します。
    • 当分の間、この変換は 3 レベルの深さのグループを処理できます ( concat(@name, '|', ancestor::*[1]/@name, '|', ancestor::*[2]/@name))。
    • 必要に応じて、同じ方法でさらにレベルを追加します。
    • の親のグループ名 (キーsowhat) は です。これは、その論理グループname2|name1||の他のグループに適用されます。<layer2>
  3. XSLT エンジンが を含む要素に遭遇するたびに@name
    • その要素のキーを計算します( $myKey)。
    • 同じキー ( ) を持つ要素のグループを取得します$myGroup
    • 現在の要素がグループ内の最初の要素かどうかを調べ、そうであれば出力にコピーします
    • 事実上、これはキーによって要素をグループ化します (この手法はMuenchian グループ化と呼ばれます)。
    • 次に、再帰的な手順を実行します。そのグループの子の処理を開始します ( $myGroup/*)。
    • 事実上、これにより正方形 0 に戻り、アルゴリズムが最初から開始されます。

私のコードには、必ずしも入力と一致しない可能性のあるいくつかの仮定/制限があります。

  • @name要素は、他のプロパティではなく、要素によってマージされるべきです。
  • 同じ@name祖先を持つ要素には特別な属性がないため、特定のグループの最初の要素を除いてすべての要素を破棄しても、データが失われることはありません。
  • 入れ子の深さは有限です。
  • マージ可能な要素は、マージ不可能な要素の子孫になることはありません (内に a が<layer>なくても)@name<layer>@name
  • おそらく、今私の心をすり抜ける他の人たち。

読書のおすすめ

  • テンプレート マッチングと XSLT プロセッサの一般的な動作メカニズム
  • XSL のデフォルト ルール
  • XPath
  • XSL キーと Muenchian グループ化
  • ID テンプレート
  • 処理フロー全体の現在のノードの概念
于 2014-11-18T10:38:44.090 に答える