Reputation: 721
I'm facing an issue while transforming XML like I can't able to fetch the elements in their correct order. Those elements are random and can't predict the order they came.
Here is my XML
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="test.xsl"?>
<toc>
<layout>
<header>Item 1</header>
<tocItem>item one - a</tocItem>
<tocItem>item one - b</tocItem>
<header>Item 2</header>
<tocItem>item two - a</tocItem>
<tocItem>item two - b</tocItem>
<tocItem>item two - c</tocItem>
<tocItem>item two - d</tocItem>
<tocItem>item two - e</tocItem>
<header>Item 3</header>
<tocItem>item three - a</tocItem>
<header>Item 4</header>
<tocItem>item four - a</tocItem>
<tocItem>item four - b</tocItem>
<tocItem>item four - c</tocItem>
<header>Item 5</header>
<tocItem>item five - a</tocItem>
<tocItem>item five - b</tocItem>
</layout>
<layout>
<header>Item 1</header>
<tocItem>item one - a</tocItem>
<tocItem>item one - b</tocItem>
<header>Item 2</header>
<tocItem>item two - a</tocItem>
</layout>
<layout>
<header>Item 1</header>
<tocItem>item one - a</tocItem>
<tocItem>item one - b</tocItem>
<tocItem>item one - c</tocItem>
<tocItem>item one - d</tocItem>
<tocItem>item one - e</tocItem>
<header>Item 2</header>
<tocItem>item two - c</tocItem>
<tocItem>item two - d</tocItem>
<tocItem>item two - e</tocItem>
<header>Item 4</header>
<tocItem>item four - a</tocItem>
<tocItem>item four - b</tocItem>
<header>Item 5</header>
<tocItem>item five - a</tocItem>
</layout>
</toc>
And here goes XSL
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Title</title>
</head>
<body>
<div class="toc">
<xsl:for-each select="/toc/layout">
<div class="layout">
<xsl:for-each select="/toc/layout/header">
<div class="header">
<p><xsl:value-of select="header" /></p>
</div>
</xsl:for-each>
<xsl:for-each select="/toc/layout/tocItem">
<div class="tocItem">
<p><xsl:value-of select="tocItem" /></p>
</div>
</xsl:for-each>
</div>
</xsl:for-each>
</div>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
When I tried the above method, it is just repeating the first header element and first tocItems. And I got all the elements when trying this code <xsl:value-of select="." />
inside the layout div. My goal is to fetch them as one by one order. Like below.
Items 1
item one - a
item one - b
Items 2
item two - a
item two - b
item two - c
Upvotes: 0
Views: 131
Reputation: 167696
In general, if you want to just transform all those elements to HTML div
with a class
attribute based on the element name then one template suffices doing that:
<xsl:template match="toc | layout | header | tocItem">
<div class="{local-name()}">
<xsl:apply-templates/>
</div>
</xsl:template>
And to preserve the input order it is best or at least easiest to simply apply-templates
.
An example is
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="#all"
version="3.0">
<xsl:mode on-no-match="shallow-copy"/>
<xsl:output method="html" indent="no" html-version="5"/>
<xsl:template match="/">
<html>
<head>
<title>.NET XSLT Fiddle Example</title>
</head>
<body>
<xsl:apply-templates/>
</body>
</html>
</xsl:template>
<xsl:template match="toc | layout | header | tocItem">
<div class="{local-name()}">
<xsl:apply-templates/>
</div>
</xsl:template>
</xsl:stylesheet>
That uses the XSLT 3 only declaration <xsl:mode on-no-match="shallow-copy"/>
to set up the identity transformation as a default processing but in earlier versions you can simply spell that out as
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
See https://xsltfiddle.liberty-development.net/ncdD7ne to experiment with it online.
Upvotes: 1
Reputation: 163458
I haven't examined what you are trying to achieve but your xsl:for-each
is clearly wrong. When you write <xsl:for-each select="/toc/layout">
, then the context node within the for-each is a <layout>
element and one would expect further selections to be relative to that element, rather than absolute paths from the root of the document. I don't understand why you have two levels of xsl:for-each
in the first place.
Upvotes: 1