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>
 </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!