2011-10-06 116 views
4

任何人都可以請幫助我進行以下轉換嗎?XSLT壓扁XML

下面是輸入XML:

<?xml version="1.0" encoding="UTF-8"?> 
<book> 
    <title>My book</title> 
    <pages>200</pages> 
    <size>big</size> 
    <author> 
     <name>Smith</name> 
    </author> 
    <author> 
     <name>Wallace</name> 
    </author> 
    <author> 
     <name>Brown</name> 
    </author> 
</book> 
<book> 
    <title>Other book</title> 
    <pages>100</pages> 
    <size>small</size> 
    <author>King</author> 
</book> 
<book> 
    <title>Pretty book</title> 
    <pages>150</pages> 
    <size>medium</size> 
</book> 

這是所需的輸出

<book style="even"> 
    <title>My book</title> 
    <pages>200</pages> 
    <size>big</size> 
    <author-name>Smith</author-name> 
</book> 
<book style="odd"> 
    <title>My book</title> 
    <pages>200</pages> 
    <size>big</size> 
    <author-name>Wallace</author-name> 
</book> 
<book style="even"> 
    <title>My book</title> 
    <pages>200</pages> 
    <size>big</size> 
    <author-name>Brown</author-name> 
</book> 
<book style="odd" > 
    <title>Other book</title> 
    <pages>100</pages> 
    <size>small</size> 
    <author-name>King</author-name> 
</book> 
<book style="even"> 
    <title>Pretty book</title> 
    <pages>150</pages> 
    <size>medium</size> 
    <author-name /> 
</book> 

我使用xsl:for-each循環試過,但我想他們把我帶到了一個死衚衕。這裏棘手的部分是無論在任何書籍中放置多少個作者標籤,​​「樣式」屬性都需要成爲「全局」。

回答

1

這個樣式表第一家門店的所有作者節點以及所有book節點不經作者在全球變量。 「/」。按文檔順序對它們進行排序。然後主模板迭代該變量中的所有節點,並根據序列中的位置生成輸出。

<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> 
    <xsl:variable name="authors" select="(//author | //book[not(author)])/."/> 

    <xsl:template match="/"> 
    <xsl:element name="result"> 
     <xsl:for-each select="$authors"> 
     <xsl:apply-templates select="."> 
      <xsl:with-param name="position" select="position()+1"/> 
     </xsl:apply-templates> 
     </xsl:for-each> 
    </xsl:element> 
    </xsl:template> 

    <xsl:template match="text()|title|pages|size"> 
    <xsl:copy> 
     <xsl:apply-templates/> 
    </xsl:copy> 
    </xsl:template> 

    <xsl:template match="book"> 
    <xsl:param name="position" select="1"/> 
    <xsl:element name="book"> 
     <xsl:attribute name="style"> 
     <xsl:if test="$position mod 2 = 0">even</xsl:if> 
     <xsl:if test="$position mod 2 = 1">odd</xsl:if> 
     </xsl:attribute> 
     <xsl:apply-templates select="title"/> 
     <xsl:apply-templates select="pages"/> 
     <xsl:apply-templates select="size"/> 
     <xsl:element name="author-name"/> 
    </xsl:element> 
    </xsl:template> 

    <xsl:template match="author"> 
    <xsl:param name="position" select="1"/> 
    <xsl:element name="book"> 
     <xsl:attribute name="style"> 
     <xsl:if test="$position mod 2 = 0">even</xsl:if> 
     <xsl:if test="$position mod 2 = 1">odd</xsl:if> 
     </xsl:attribute> 
     <xsl:apply-templates select="../title"/> 
     <xsl:apply-templates select="../pages"/> 
     <xsl:apply-templates select="../size"/> 
     <xsl:element name="author-name"> 
     <xsl:if test="name"> 
      <xsl:value-of select="name"/> 
     </xsl:if> 
     <xsl:if test="not(name)"> 
      <xsl:value-of select="."/> 
     </xsl:if> 
     </xsl:element> 
    </xsl:element> 
    </xsl:template> 
</xsl:stylesheet> 
+0

嗯,不能得到這個工作。我得到以下錯誤:「與此樣式表中另一個模板的模板衝突」。即使我進行改造,我也只能得到最後一本書... –

+0

對不起,有一個多餘的模板/我忘了刪除,它現在被糾正。但奇怪的是,我用XSLT引擎成功嘗試了它,並沒有抱怨這一點。另外,我在輸入文檔中添加了一個根元素,這也可能是導致不同行爲的原因。 –

+0

我不知道爲什麼,但這隻適用於Xalan處理器,不適用於包含在JRE中的標準處理器。 –

0

(修訂)

<xsl:for-each "//author | /book[not(author)]" /> 
    <xsl:variable name="style" select="('even','odd')[(position() mod 2) + 1]" /> 
    <xsl:apply-templates select="."><xsl:with-param name="style" select="$style" /></xsl:apply-templates> 
</xsl:for-each> 

然後在你的模板的作者,你可以使用構造book元素..

+0

因爲沒有作者 –

+0

('even','odd')[(position()mod 2)+ 1]不是有效的XPath表達式,所以不會選擇「Pretty Book」 –

+0

我認爲它可能需要XPath 2 –

7

這個簡單的,純XSLT 1.0轉化(沒有條件句,沒有xsl:for-each,沒有參數傳遞,沒有xsl:element,沒有用的臭名昭著低效//

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

    <my:names> 
    <n>odd</n> 
    <n>even</n> 
    </my:names> 

    <xsl:variable name="vStyles" 
     select="document('')/*/my:names/*"/> 

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

    <xsl:template match="book/author"> 
    <xsl:variable name="vPos"> 
     <xsl:number level="any" count="book/author|book[not(author)]"/> 
    </xsl:variable> 
     <book style="{$vStyles[$vPos mod 2 +1]}"> 
      <xsl:copy-of select="@*|../node()[not(self::author)]"/> 
      <author-name> 
      <xsl:value-of select="normalize-space()"/> 
     </author-name> 
     </book> 
    </xsl:template> 

    <xsl:template match="book[author]"> 
    <xsl:apply-templates/> 
    </xsl:template> 

    <xsl:template match="book[not(author)]"> 
    <xsl:variable name="vPos"> 
     <xsl:number level="any" count="book/author|book[not(author)]"/> 
    </xsl:variable> 
     <book style="{$vStyles[$vPos mod 2 +1]}"> 
      <xsl:copy-of select="@*|node()"/> 
      <author-name/> 
     </book> 
    </xsl:template> 

    <xsl:template match="book[author]/*[not(self::author)]"/> 
</xsl:stylesheet> 

當施加到這個XML文檔(提供的一個包裝成一個頂部元素):

<t> 
    <book> 
     <title>My book</title> 
     <pages>200</pages> 
     <size>big</size> 
     <author> 
      <name>Smith</name> 
     </author> 
     <author> 
      <name>Wallace</name> 
     </author> 
     <author> 
      <name>Brown</name> 
     </author> 
    </book> 
    <book> 
     <title>Other book</title> 
     <pages>100</pages> 
     <size>small</size> 
     <author>King</author> 
    </book> 
    <book> 
     <title>Pretty book</title> 
     <pages>150</pages> 
     <size>medium</size> 
    </book> 
</t> 

正好產生想要的,正確的結果

<t> 
    <book style="even"> 
     <title>My book</title> 
     <pages>200</pages> 
     <size>big</size> 
     <author-name>Smith</author-name> 
    </book> 
    <book style="odd"> 
     <title>My book</title> 
     <pages>200</pages> 
     <size>big</size> 
     <author-name>Wallace</author-name> 
    </book> 
    <book style="even"> 
     <title>My book</title> 
     <pages>200</pages> 
     <size>big</size> 
     <author-name>Brown</author-name> 
    </book> 
    <book style="odd"> 
     <title>Other book</title> 
     <pages>100</pages> 
     <size>small</size> 
     <author-name>King</author-name> 
    </book> 
    <book style="even"> 
     <title>Pretty book</title> 
     <pages>150</pages> 
     <size>medium</size> 
     <author-name/> 
    </book> 
</t> 

說明:適當利用xsl:number和模板/模式匹配。

+0

幾乎請注意,在提供的輸出中,最後一本書中包含空的'author-name'節點 –

+0

當然 - 當我開始工作時我會糾正這個問題 - 我正要離開家。 –

+0

你如何設法讓事情看起來如此簡單! – Treemonkey