Is this possible in XSLT (logic related)?

H

Hvid Hat

I've got a series of documents in my XML data. The documents have a given
width. I need to style the documents so the documents with a width of 100
are in their own line while other documents are grouped two in a line. There
is always a maximum of 2 columns so it's not possible to have 3 documents
with a width of 33 in one line.

So I want my data.xml to results in the following:

<div class="row">
<div>DocumentA</div>
</div>
<div class="row">
<div>DocumentB</div>
<div>DocumentC</div>
</div>
<div class="row">
<div>DocumentD</div>
<div>DocumentE</div>
</div>

- data.xml -

<?xml version="1.0" encoding="ISO-8859-1"?>
<?xml-stylesheet type="text/xsl" href="style.xsl"?>
<documents>
<document>
<width>100</width>
<content>Document A</content>
</document>
<document>
<width>66</width>
<content>Document B</content>
</document>
<document>
<width>33</width>
<content>Document C</content>
</document>
<document>
<width>50</width>
<content>Document D</content>
</document>
<document>
<width>50</width>
<content>Document E</content>
</document>
</documents>

- style.xsl -

<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="document">
<html>
<head>
<title>XSLT</title>
</head>
<body>
<xsl:choose>
<xsl:when test="width=100">
<div class="row">
<div><xsl:value-of select="content"/></div>
</div>
</xsl:when>
<!-- Pseudo begin -->
<xsl:eek:therwise>
<div class="row">
<div><xsl:value-of select="this.content"/></div>
<div><xsl:value-of select="next.content"/></div>
next.skip
</div>
</xsl:eek:therwise>
<!-- Pseudo end -->
</xsl:choose>
</body>
</html>
</xsl:template>
</xsl:stylesheet
 
D

David Carlisle

Hvid said:
I've got a series of documents in my XML data. The documents have a
given width. I need to style the documents so the documents with a width
of 100 are in their own line while other documents are grouped two in a
line. There is always a maximum of 2 columns so it's not possible to
have 3 documents with a width of 33 in one line.


most grouping problems are easier in xslt 2 tahn xslt 1, but Om assuming
you want xslt 1 as that's what your example code used.


<?xml version="1.0" encoding="ISO-8859-1"?>
<?xml-stylesheet type="text/xsl" href="style.xsl"?>
<documents>
<document>
<width>100</width>
<content>Document A</content>
</document>
<document>
<width>66</width>
<content>Document B</content>
</document>
<document>
<width>33</width>
<content>Document C</content>
</document>
<document>
<width>50</width>
<content>Document D</content>
</document>
<document>
<width>50</width>
<content>Document E</content>
</document>
</documents>




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

<xsl:template match="documents">
<html>
<head>
<title>XSLT</title>
</head>
<body>
<xsl:apply-templates select="document[1]"/>
</body>
</html>
</xsl:template>

<xsl:template match="document[width=100]">
<div class="row1">
<xsl:apply-templates/>
</div>
<xsl:apply-templates select="following-sibling::document[1]"/>
</xsl:template>

<xsl:template match="document">
<div class="row">
<xsl:apply-templates/>
<xsl:apply-templates
select="following-sibling::document[1][width!=100]/content"/>
</div>
<xsl:apply-templates
select="(.|following-sibling::document[1][width!=100])[last()]
/following-sibling::document[1]"/>
</xsl:template>

<xsl:template match="width"/>

<xsl:template match="content">
<div><xsl:apply-templates/></div>
</xsl:template>

</xsl:stylesheet>


$ saxon data.xml data.xsl
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">

<title>XSLT</title>
</head>
<body>
<div class="row1">
<div>Document A</div>
</div>
<div class="row">
<div>Document B</div>
<div>Document C</div>
</div>
<div class="row">
<div>Document D</div>
<div>Document E</div>
</div>
</body>
</html>
 
H

Hvid Hat

Hello David,
most grouping problems are easier in xslt 2 tahn xslt 1, but Om
assuming you want xslt 1 as that's what your example code used.

Very nice, David. Thanks! Now, I also want to learn something so could you
explain the line below?

<xsl:apply-templates select="(.|following-sibling::document[1][width!=100])[last()]/following-sibling::document[1]"/>

Apply to the first following sibling with a width different from 100 and
then what? I'm confused about last(). Is the .| necessary? I tried removing
it and couldn't see a difference
 
J

Joseph Kesselman

Hvid said:
Very nice, David. Thanks! Now, I also want to learn something so could
you explain the line below?

<xsl:apply-templates
select="(.|following-sibling::document[1][width!=100])[last()]/following-sibling::document[1]"/>

As with any programming language, break the expression up and think
about it in stages.

(.|following-sibling::document[1][width!=100])

A list made up of the current node (.) and the first <document> sibling
after the current node if and only if its width is not 100.

.... [last()]

The last node in that list. IE, the following <document> if it met the
test (width!=100), otherwise the current node.

.... /following-sibling::document[1]

The first <document> sibling after the node we just selected. In other
words, if the next <document> has a width of 100, the one after that;
otherwise, that next <document>.


The only complicated thing here is the trick of building a
one-or-two-node long list and then taking it apart, as a way to say
"that if found, otherwise this."
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,768
Messages
2,569,574
Members
45,048
Latest member
verona

Latest Threads

Top