...">

XSLT for XML alignment

Can someone help me with the following conversion?

Here is the xml input:

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

This is the desired result.

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

I tried using xsl:for-each loops, but I suppose they led me to a dead end. The hard part here is the attribute of the style, which somehow has to be “global”, regardless of how many author tags are placed in any book.

+4
source share
3 answers

This style sheet first stores all the nodes of the author, as well as all nodes of books without authors in a global variable. "/." sorts them in document order. Then, the main template iterates over all nodes of this variable and generates output in accordance with the position in the sequence.

 <?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> 
+1
source

This is a simple, pure XSLT 1.0 conversion (no conditional expressions, no xsl:for-each , no parameter passing, no xsl:element , no sadly inefficient // ) :

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

as applied to this XML document (provided that it is wrapped in one top element):

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

produces exactly the necessary, correct result :

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

The explanation . Appropriate use of xsl:number and pattern / pattern matching.

+7
source

(revised)

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

Then, in the author’s template, you can create book elements using ..

0
source

All Articles