2011-01-24 11 views
8

特定の条件が満たされている場合、XSLTを使用してノードを1レベル上に移動する方法を知りたいと思います。あなたに例を挙げてみると、次のXMLソースを見てください。XSLT:ノードを1レベル上に移動

<Settings> 
    <String [...]> 
    <Boolean [...]/> 
    </String> 
</Settings> 

これは、私が開始状況として持っているXMLです。明確にするために、ノード名 "Settings"、 "String"、 "Boolean"は、定義した特別なノードです。

問題は、 "ブール"ノードが "文字列"ノードの内部で使用できないことです。だからこそ私はそれらの "ブール"ノードをレベルアップさせる必要があります。希望XMLは次のようになります。

<Settings> 
    <String [...]></String> 
    <Boolean [...]/> 
</Settings> 

XSLTにもかかわらず、XMLツリー内の位置の、兄弟ブールノードを持つすべての文字列のノードで動作するように持っています。

<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet version="2.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"   
    xmlns:fo="http://www.w3.org/1999/XSL/Format" 
    xmlns:xs="http://www.w3.org/2001/XMLSchema" 
    xmlns:fn="http://www.w3.org/2005/xpath-functions"> 

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

    <!-- special rules ... --> 

</xsl:stylesheet> 

を私は苦労していなことがある:

は、これまでのところ私は、あなたが最初に目的の変換のためにいくつかの特別なルールを適用し、「アイデンティティのルール」を使用してXMLのすべてをコピーしなければならないことを学びましたルールを使用して、「文字列」ノードの兄弟であるすべての「ブール」ノードを1レベル上に移動します。どうやってやるの?!?

+0

良い質問、+1。 "アイデンティティルールを上書きする"デザインパターンのバリエーションについては、私の答えを見てください - 私は少し正確なオーバーライドを提供しました。 :) –

答えて

6

私の解釈は、このソリューションは、@ Michae-ケイのものと非常によく似て

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

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

<xsl:template match="String"> 
    <xsl:copy> 
     <xsl:apply-templates select="child::node()[not(self::Boolean)]"/> 
    </xsl:copy> 
    <xsl:apply-templates select="Boolean"/> 
</xsl:template> 

</xsl:stylesheet> 
+1

マイケルありがとう。あなたの答えはうまくいくようです。唯一のマイナーな変更を提案するのみ: は ます。 は ます。 この変更により、Stringノードの属性もコピーされます。どうもありがとうございました。 – Jens

+0

+1正解です。 –

3

は、以下のことを試してみてください。要件の

<!-- copy all --> 
<xsl:template match="*"> 
    <xsl:copy> 
     <xsl:copy-of select="@*" /> 
     <xsl:apply-templates /> 
    </xsl:copy> 
</xsl:template> 

<!-- ignore booleans-inside-strings --> 
<xsl:template match="String/Boolean" /> 

<!-- place the booleans-inside-strings into the settings element --> 
<xsl:template match="Settings"> 
    <xsl:copy> 
     <xsl:copy-of select="//String/Boolean" /> 
     <xsl:apply-templates /> 
    </xsl:copy> 
</xsl:template> 
+1

「すべてコピー」テンプレートに 'match =" @ * | node() "'と 'select =" @ * | node() "'という理由がありますか?ちょうど好奇心... – Filburt

+0

あなたの答えをありがとう。それは私の例でうまくいく。しかし、ブール値ノードは必ず設定要素にコピーされるため、常に動作しません。ルールはブール要素を1レベル上にコピーする必要があります。変換する必要があり を考える:また Jens

+0

、なぜ始まる '//' '//文字列/ Boolean'で? –

3

としてソリューションを提供します。しかし、アイデンティティルールのオーバーライドは、もう少し正確である - 実際にBoolean子供を持っている唯一のString要素が一致している:

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

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

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

この変換は、次のXMLドキュメントに対して適用される場合:

<Settings> 
    <String> 
     <Boolean /> 
    </String> 
    <String/> 
</Settings> 

指名手配、正しい結果がが生成されます

<Settings> 
    <String/> 
    <Boolean/> 
    <String/> 
</Settings> 
+0

私の答えを見てもらえますか?私はそこでdownvotingの価値がある間違いを見つけることができません。私はdownvote自体について気にしない、ちょうど私がいくつかの大失敗を逃したかどうかを見たいと思う。 – Flack

+0

@Flack:あなたの解決策はOKだと思います。 'Setings'の属性にテンプレートを適用する必要があります。そうでなければ、それらは失われます。私はあなたの答えをupvotedしていますが、この推奨された修正も加えてください。 –

+0

OPが提供したサンプルのため、意識的に省略されました。私は私の答えを取り除くことを選んだが、より良い設計の2つがあるので、答えを選んだ。もちろん、アップヴォート。利用可能な投票の復活を待っていた。 – Flack

関連する問題