Reputation: 2636
I need to construct a string from numbers located in different nodes in my xml source, but the caveats are that the datarate nodes order will be random and the starting number has to be start with at least 600. If there is no 600, then start with 800.
<datarate rate="200" />
<datarate rate="600" />
<datarate rate="300" />
<datarate rate="400" />
<datarate rate="800" />
<datarate rate="1000" />
http://example.com/src/600/800/
I've tried sorting based on groups, but to no avail. Anyone out there have an idea?
Thanks for any help you can provide!
Upvotes: 1
Views: 185
Reputation: 243449
This short and simple transformation (no explicit conditional instruction used at all -- no xsl:choose
, no xsl:when
, no xsl:otherwise
):
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/*">
<t>
<xsl:apply-templates select="*">
<xsl:sort select="@rate" data-type="number"/>
</xsl:apply-templates>
</t>
</xsl:template>
<xsl:template match=
"datarate
[not(@rate >= 600)
or
not(../*[@rate = 600]) and not(@rate >= 800)
]"/>
</xsl:stylesheet>
when applied on the provided XML document (wrapped into a single top element to be made well-formed):
<t>
<datarate rate="200" />
<datarate rate="600" />
<datarate rate="300" />
<datarate rate="400" />
<datarate rate="800" />
<datarate rate="1000" />
</t>
produces the wanted, correct result:
<t>
<datarate rate="600"/>
<datarate rate="800"/>
<datarate rate="1000"/>
</t>
when applied on the following, slightly changed XML document (no rate of 600, but rates of 601 and 650):
<t>
<datarate rate="200" />
<datarate rate="601" />
<datarate rate="650" />
<datarate rate="300" />
<datarate rate="400" />
<datarate rate="800" />
<datarate rate="1000" />
</t>
again the correct result is produced:
<t>
<datarate rate="800"/>
<datarate rate="1000"/>
</t>
Upvotes: 0
Reputation: 9863
With XSLT 2 you can do this:
<xsl:template match="/">
<xsl:for-each select="//datarate[number(@rate) ge 600]">
<xsl:sort select="@rate" data-type="number"/>
<xsl:value-of select="@rate"/>
<xsl:if test="not(position() eq last())">
<xsl:text>, </xsl:text>
</xsl:if>
</xsl:for-each>
</xsl:template>
Upvotes: 1
Reputation: 6115
If you knew the threshold number upfront you could do a very simple transform like this:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" encoding="UTF-8"/>
<xsl:template match="/">
<xsl:apply-templates select="//datarate">
<xsl:sort select="@rate" data-type="number"/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="datarate[@rate < 600]"/>
<xsl:template match="datarate">
[<xsl:value-of select="@rate"/>]
</xsl:template>
</xsl:stylesheet>
Since you need to check if there's a 600
and use 800
as your threshold if no 600
found, you could it like this:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" encoding="UTF-8"/>
<xsl:variable name="threshold">
<xsl:choose>
<xsl:when test="//datarate[@rate = 600]">600</xsl:when>
<xsl:otherwise>800</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:template match="/">
<xsl:apply-templates select="//datarate">
<xsl:sort select="@rate" data-type="number"/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="datarate[@rate < $threshold]"/>
<xsl:template match="datarate">
[<xsl:value-of select="@rate"/>]
</xsl:template>
</xsl:stylesheet>
In the event there might be neither a 600
nor a 800
you might want to add some more logic to the $threshold
variable declaration.
p.s. Having no details about how you would like your string constructed I just printed the @rate
values enclosed in []
.
Upvotes: 0