2011-10-06 120 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