Reputation: 2404
I have some xml and I would like to dynamically extract some information, based on some incoming data.
Here is some xml:
<?xml version="1.0" encoding="UTF-8"?>
<releaseNote>
<name>DECOUPLING_client</name>
<change>
<date hour="12" day="24" second="44" year="2012" month="10" minute="46"/>
<submitter>Automatically Generated</submitter>
<description>ReleaseNote Created</description>
</change>
<change>
<version>0-2</version>
<date hour="12" day="24" second="48" year="2012" month="11" minute="46"/>
<submitter>fred.darwin</submitter>
<description> first iteration of decoupling client - copied files from old decoupling module</description>
<install/>
</change>
<change>
<version>0-3</version>
<date hour="16" day="25" second="34" year="2012" month="11" minute="52"/>
<submitter>fred.darwin</submitter>
<description> promoting changes</description>
<install/>
</change>
</releaseNote>
And I'd like to pass in the string '0-2' and find out all versions since 0-2 like this:
0-3 fred.darwin 25/11/2012 promoting changes
It's complicated by the fact that the numbers I'm comparing start with '0-'.
However luckily you can remove the '0-' and get a real number, which corresponds to a position, so I've got as far as something like this:
xmllint --xpath '/releaseNote/change[position()>2]/description/text() ${file}
which just concatenates all the descriptions and spits them out.
How do I loop through them and select multiple node content?
Upvotes: 1
Views: 1615
Reputation: 2585
Looks like you already found a solution, but just to offer an alternative: if you don't mind using XSLT, you could also have an stylesheet file like this:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" version="1.0" encoding="utf-8"/>
<xsl:param name="version"/>
<!-- Strip white-space-only text nodes in all elements -->
<xsl:strip-space elements="*"/>
<xsl:variable name="version-after-hyphen" select="number(substring-after($version, '-'))"/>
<!-- XML entity for a tab -->
<xsl:variable name="DELIMITER" select="'	'"/>
<xsl:template match="/">
<!--
Apply every <change> element with a <version> child whose value is $version
or greater.
-->
<xsl:apply-templates
select="releaseNote/change[number(substring-after(version, '-')) >= $version-after-hyphen]"/>
</xsl:template>
<xsl:template match="change">
<xsl:apply-templates/>
<!-- Insert a newline after every <change> element -->
<xsl:text> </xsl:text>
</xsl:template>
<xsl:template match="submitter | description">
<xsl:value-of select="concat($DELIMITER, normalize-space(.))"/>
</xsl:template>
<xsl:template match="version">
<xsl:value-of select="."/>
</xsl:template>
<xsl:template match="date">
<!-- Format date -->
<xsl:value-of select="concat($DELIMITER, @day, '/', @month, '/', @year, ' ', @hour, ':', @minute)"/>
</xsl:template>
</xsl:stylesheet>
You could then run it with xsltproc
e.g. like this:
xsltproc --stringparam version 0-2 stylesheet.xsl releaseNote.xml
And the output would be:
0-2 24/11/2012 12:46 fred.darwin first iteration of decoupling client - copied files from old decoupling module
0-3 25/11/2012 16:52 fred.darwin promoting changes
I'm fairly certain it'll be faster than executing xmllint
multiple times and perhaps somewhat easier to maintain in the long run as well. libxml2
(which you already have installed since you have xmllint
) includes xsltproc
, too, so that shouldn't be a problem, either.
Upvotes: 1
Reputation: 2404
Ok so I got it working like this:
#first count number of nodes ie how many changes (could be eg 979)
numChanges=`xmllint --xpath 'count(/releaseNote/change)' ${MPATH}/${mod}/resources/ReleaseNote.xml`
echo "found $numChanges changes"
#even though last one shows as 0-952
lastModule=`xmllint --xpath '/releaseNote/change[last()]/version/text()' ${MPATH}/${mod}/resources/ReleaseNote.xml`
#so
#then loop through from our one to the end
#use a unix loop
echo "version number ${versionNumber} num changes ${numChanges}"
#for i in {${versionNumber}..${numChanges}}; do
i=$versionNumber
while [[ $i -le $numChanges ]] ; do
#and for each item in the list spit out description, version, submitter and try to parse date
xmllint --xpath "/releaseNote/change[$i]/version/text()" ${MPATH}/${mod}/resources/ReleaseNote.xml
echo -en ' \t '
xmllint --xpath "string(/releaseNote/change[$i]/date/@day)" ${MPATH}/${mod}/resources/ReleaseNote.xml
echo -en '/'
xmllint --xpath "string(/releaseNote/change[$i]/date/@month)" ${MPATH}/${mod}/resources/ReleaseNote.xml
echo -en '/'
xmllint --xpath "string(/releaseNote/change[$i]/date/@year)" ${MPATH}/${mod}/resources/ReleaseNote.xml
echo -en ' '
xmllint --xpath "string(/releaseNote/change[$i]/date/@hour)" ${MPATH}/${mod}/resources/ReleaseNote.xml
echo -en ':'
xmllint --xpath "string(/releaseNote/change[$i]/date/@minute)" ${MPATH}/${mod}/resources/ReleaseNote.xml
echo -en ' \t '
xmllint --xpath "/releaseNote/change[$i]/submitter/text()" ${MPATH}/${mod}/resources/ReleaseNote.xml
echo -en ' \t '
xmllint --xpath "/releaseNote/change[$i]/description/text()" ${MPATH}/${mod}/resources/ReleaseNote.xml
((i = i + 1))
echo
done
Output looks like this:
0-96 21/4/2014 17:56 onkar.sharma test case for subscription validation
0-97 28/5/2014 15:58 trushant.patel JIRAET81
0-98 9/6/2014 18:10 vivek.mittal Refinement for GetFindPackagesWithService flow
It's much slower than when I was using grep and tr, but it does allow me to parse the date correctly and it looks exactly as I wanted.
Success!
Upvotes: 0