Re: [xsl] Adding an element to a list of similar elements?

Subject: Re: [xsl] Adding an element to a list of similar elements?
From: "Jim Earley" <xml.jim@xxxxxxxxx>
Date: Sat, 5 Apr 2008 00:13:35 -0600
Dan,

You could try something like this:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"; version="1.0">
    <xsl:param name="to_add" select="''"/>
    <xsl:template match="node() | @*">
        <xsl:copy>
            <xsl:apply-templates select="node() | @*" />
        </xsl:copy>
    </xsl:template>
    <xsl:template match="/cruisecontrol/project.fullbuild">
        <xsl:copy>
            <xsl:copy-of select="node() | @*"/>
        </xsl:copy>
        <xsl:if test="not(following-sibling::project.fullbuild)">
            <project.fullbuild name="{$to_add}" buildAfterFailed="false"/>
        </xsl:if>
    </xsl:template>
</xsl:stylesheet>


Cheers,

Jim Earley

On Fri, Apr 4, 2008 at 10:07 PM, Dan Stromberg
<dstromberglists@xxxxxxxxx> wrote:
>
> This feels incredibly simple - the sort of thing that should be in 62
> different web-based XSLT tutorials, but I've been googling for quite a while
> now, and I don't see much (anything) on the topic.  This is about my 5th
> XSLT script, so I'm more than a bit of a newb.
>
> All I want to do is add an element to an xml document after a bunch of
> similar elements - hopefully with just one attribute changed relative to the
> similar line before it, or with a skeletal element if there isn't a similar
> element already in the file.  I'm willing to do xpath queries to list what's
> in the file now, and run one or another XSLT script depending on what kind
> of change is needed, using some other language like bash or python to
> control which XSLT kicks in.
>
> I'm starting to feel like I should ignore XSLT and use a DOM-based Python
> script, but hopefully this list can save me from that (mostly because I
> believe it'd toast the comments, and I like comments :) .
>
> I have a basic XML document I'm testing with (it comes from cruisecontrol, a
> java-based automated build system) :
>
> <?xml version="1.0"?>
> <cruisecontrol>
>  <project.mergeanddelete.dist name="db" buildAfterFailed="false"/>
>  <project.mergeanddelete.dist name="DScripts" buildAfterFailed="false">
>      <property name="log.mergedir" value="checkout/DScripts/dist"/>
>  </project.mergeanddelete.dist>
>  <project.fullbuild name="3.1.2-dev" buildAfterFailed="false"/>
>  <project.fullbuild name="3.1.3-dev" buildAfterFailed="false"/>
> </cruisecontrol>
>
> And I just want to add <project.fullbuild name="3.1.4-ga"
> buildAfterFailed="false"/> after <project.fullbuild name="3.1.3-dev"
> buildAfterFailed="false"/> ideally using the 3.1.3-dev line as a template
> for the new 3.1.4 line.
>
> I experimented a bunch on my own with matching the last() project.fullbuild
> and trying to output two elements on it instead of one, but that seems to be
> going nowhere despite too many variations and machinations to count (you
> don't want to see all the things I tried - too much for the list).  Is this
> at all a reasonable approach in standard XSLT?  After more googling, I saw
> something saying that you shouldn't try to add attributes after a child, and
> I'm not sure if I was running afoul of that or not.  I just kept getting the
> last() element nicely, and then a new element with empty attributes - not
> much in the way of a helpful error message, not even with --verbose.
>
> Here's -one- of the many things I tried based on this approach:
>
> <xsl:stylesheet version="1.0"
> xmlns:xsl="http://www.w3.org/1999/XSL/Transform";>
>  <xsl:template match="node() | @*">
>    <xsl:copy>
>       <xsl:apply-templates select="node() | @*" />
>    </xsl:copy>
>  </xsl:template>
>  <xsl:template match="/cruisecontrol/project.fullbuild[last()]">
>    <xsl:copy>
>       <xsl:copy-of select="node() | @*"/>
>    </xsl:copy>
>    <xsl:text>&#xA;    </xsl:text>
>    <xsl:element name="project.fullbuild">
>       <xsl:attribute name="name" value="${to_add}"/>
>    </xsl:element>
>  </xsl:template>
> </xsl:stylesheet>
>
> That {$to_add} is coming from a --string-param on the command line - but I'm
> not even getting a proper name attribute -  it comes out a null string.
>
> I'm using xsltproc on an openSUSE 10.3 system:
>
> $ links -dump /tmp/t.html | sed '/^ *$/d'
>  XSL version: 1.0
>  Vendor: libxslt
>  Vendor URL: http://xmlsoft.org/XSLT/
>  Product name: [Undefined]
>  Product version: [Undefined]
>  Is schema-aware: [Undefined]
>  Supports serialization: [Undefined]
>  Supports backwards compatibility: [Undefined]
>
> $ xsltproc --version
> Using libxml 20630, libxslt 10120 and libexslt 813
> xsltproc was compiled against libxml 20630, libxslt 10120 and libexslt 813
> libxslt 10120 was compiled against libxml 20630
> libexslt 813 was compiled against libxml 20630
>
> Help me, Obi-Wan Kenobi... :)
>
> TIA!

Current Thread