[英]xpath - how to select multiple nodes based on value
I have some xml and I would like to dynamically extract some information, based on some incoming data. 我有一些xml,我想根据一些传入数据动态提取一些信息。
Here is some xml: 这是一些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-2”并找出自 0-2 以来的所有版本,如下所示:
0-3 fred.darwin 25/11/2012 promoting changes
It's complicated by the fact that the numbers I'm comparing start with '0-'. 我要比较的数字以“ 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: 但是幸运的是,您可以删除'0-'并获得一个与位置相对应的实数,因此,我得到了如下信息:
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? 如何遍历它们并选择多个节点内容?
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: 看起来您已经找到了解决方案,但仅是提供一种替代方法:如果您不介意使用XSLT,则还可以拥有一个样式表文件,如下所示:
<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
eg like this: 然后可以使用
xsltproc
运行它,例如:
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. 我相当确定,它将比多次执行
xmllint
更快,并且从长远来看,也许也更容易维护。 libxml2
(which you already have installed since you have xmllint
) includes xsltproc
, too, so that shouldn't be a problem, either. libxml2
(由于具有xmllint
安装),也包含xsltproc
,因此也不是问题。
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. 它比我使用grep和tr时要慢得多,但是它确实允许我正确解析日期,并且看起来完全符合我的要求。
Success! 成功!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.