Jump to content

Output all nodes except 1


devin

Recommended Posts

I am trying to create a template that will remove a child node from a parent and copy everything else as is. Here is some example XML:

<item><price><amt>20</amt></price><price><amt>500</amt></price><desc>this is the description</desc><node1>text</node1><node2>text 2</node2><node3 id="1">has id</node3></item>

This is what I want to end up with:

<item><price><amt>500</amt></price><desc>this is the description</desc><node1>text</node1><node2>text 2</node2><node3 id="1">has id</node3></item>

I want to take the highest price, ignore the other price and print out every other node. This is how I am doing it:

<xsl:template match="item">    <!-- start of our item -->    <item>        <xsl:choose>            <!-- if we have more then 1 price then we are going to take the biggest one -->            <xsl:when test="count(price) > 1">                <!-- get each limit amount -->                <xsl:variable name="p1" select="price[1]/amt" />                <xsl:variable name="p2" select="price[2]/amt" />                <!-- find our max -->                <xsl:variable name="max">                <xsl:choose>                    <xsl:when test="$p1 > $p2">                        <xsl:value-of select="$p1"/>                    </xsl:when>                    <xsl:when test="$p2 > $p1">                        <xsl:value-of select="$p2"/>                    </xsl:when>                    <xsl:otherwise>                        <xsl:value-of select="$p1"/>                    </xsl:otherwise>                </xsl:choose>                </xsl:variable>                               <xsl:apply-templates select="@*|desc|node1|node2|node3" />               <!-- output our price with the max amount -->               <price>                    <amt><xsl:value-of select="$max" /></amt>                </price>                         </xsl:when>                <xsl:otherwise> <!-- if we only have 1 price then just print everything                        out -->                <xsl:apply-templates select="@*|node()" />            </xsl:otherwise>        </xsl:choose>    </item></xsl:template>

So to print out all the other nodes I am doing this:<xsl:apply-templates select="@*|desc|node1|node2|node3" />But I don't really like that, I was hoping there was a way to print everything BUT the price. I tried things like this:<xsl:apply-templates select="@*|node()[.!=price] />But that didn't work. Any ideas?Thanks.

Link to comment
Share on other sites

If you use XSLT 2.0 (as you can with Saxon 9 http://saxon.sourceforge.net/ or with AltovaXML Tools http://www.altova.com/altovaxml.html) then you could simply write a template that does not copy any price elements not containing the maximun e.g.

<xsl:stylesheet  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"  xmlns:xs="http://www.w3.org/2001/XMLSchema"  exclude-result-prefixes="xs"  version="2.0">    <xsl:strip-space elements="*"/>  <xsl:output indent="yes"/>    <xsl:template match="@* | node()">	<xsl:copy>	  <xsl:apply-templates select="@*, node()"/>	</xsl:copy>  </xsl:template>    <xsl:template match="item/price[not(xs:double(amt) eq max(../price))]"/></xsl:stylesheet>

Your approach of determing the maximum and then process all child nodes except those price elements not having the maximum looks as follows:

<xsl:stylesheet  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"  xmlns:xs="http://www.w3.org/2001/XMLSchema"  exclude-result-prefixes="xs"  version="2.0">    <xsl:strip-space elements="*"/>  <xsl:output indent="yes"/>    <xsl:template match="@* | node()">	<xsl:copy>	  <xsl:apply-templates select="@*, node()"/>	</xsl:copy>  </xsl:template>    <xsl:template match="item">	<xsl:variable name="max-price" as="xs:double"	  select="max(price/amt)"/>	<xsl:copy>	  <xsl:apply-templates select="@*, node() except price[xs:double(amt) ne $max-price]"/>	</xsl:copy>  </xsl:template></xsl:stylesheet>

Does that help? Or do you need to use XSLT 1.0?

Link to comment
Share on other sites

If you must use XSLT 1.0, you can use the name() function to get the name of a node, and therefore be able to exclude it from the template applying, like:

<xsl:apply-templates select="@*|node()[name()!='price'] />

To find out the maximum, I'd reccomend you use the math:max() EXSLT function/template. If you can use the function (as opposed to the template), you can actually reduce the stylesheet to pretty much what the first XSLT 2.0 version looks like.

Link to comment
Share on other sites

Archived

This topic is now archived and is closed to further replies.

×
×
  • Create New...