2011-01-24 57 views
8

我想知道如何在遵守某些條件的情況下使用XSLT將節點向上移動一個級別。舉個例子,看看下面的XML源代碼:XSLT:將節點向上移動

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

這就是我作爲起始情況的XML。清楚的是,節點名稱「Settings」,「String」,「Boolean」是我們定義的特殊節點。

問題是「布爾」節點不允許在「字符串」節點內部。這就是爲什麼我必須將這些「布爾」節點升級。所需的XML是這樣的:

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

的XSLT還擁有具有同級布爾節點,無論在XML樹中的位置的每個字符串節點的工作。

到目前爲止,我瞭解到,你必須首先使用「身份規則」拷貝所有的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> 

我掙扎的東西是規則將所有「布爾」節點(它們是「字符串」節點的同級節點)向上移動一級。我怎樣才能做到這一點?!?

+0

好問題,+1。查看我的答案,瞭解「覆蓋身份規則」設計模式的變體 - 我提供了更準確的覆蓋。 :) – 2011-01-24 14:17:50

回答

6

我的要求解釋給出瞭解決方案,

<?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> 
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 2011-01-24 09:30:30

+0

謝謝你的回答。這對我的例子很好。但它不會始終工作,因爲它總是將布爾節點複製到設置元素中。該規則應該將布爾元素向上複製一層。想想 這應該轉化爲: Jens 2011-01-24 10:26:27

+0

另外,爲什麼開始``//在'//字符串/ Boolean`? – 2011-01-24 18:56:12

3

該解決方案是非常相似Michae凱的@。然而,身份規則壓倒一切的是多一點點精確的 - 只有String元素真的有Boolean孩子匹配:

<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>