为什么我的XMLStarlet查询在包含引号时不起作用?

时间:2016-09-06 14:09:49

标签: xml bash xmlstarlet

我有这个XML

<Result>
<Dataset name='ident1'>
 <Row name='a1'>
    <queryname>cat0</queryname>
    <superfilename>cat1</superfilename>
    <indexfilename>cat2</indexfilename>
</Row>
 <Row name='a2'>
    <queryname>cat3</queryname>
    <superfilename>cat4</superfilename>
    <indexfilename>cat5</indexfilename>
 </Row>
 <Row name='a3'>
    <queryname>cat6</queryname>
    <superfilename>cat7</superfilename>
    <indexfilename>cat8</indexfilename>
 </Row>
</Dataset>
<Dataset name='Result 2'>
</Dataset>
<Dataset name='Result 3'>
</Dataset>
<Dataset name='Result 4'>
</Dataset>
</Result>

我想计算名为ident1的DataSet的行数。我使用的xmlstarlet命令是:

xmlstarlet sel -t -v 'count(/Result/Dataset[@name='ident1']/Row)' oscar.xml

我认为它应该有效,但它返回0。

我尝试了其他变体,但所有变体都返回0。

xmlstarlet sel -t -v 'count(/Result/Dataset[@name='ident1'])' oscar.xml
xmlstarlet sel -t -v 'count(/Result/Dataset[@name='ident1'][*]/Row)' oscar.xml
xmlstarlet sel -t -v 'count(/Result/Dataset[@name='ident1']/Row[*])' oscar.xml

我做错了什么?

请注意

如果我计算其他元素如DataSet,它会正确返回4。

xmlstarlet sel -t -v 'count(/Result/Dataset)' oscar.xml

1 个答案:

答案 0 :(得分:2)

在这里,引号都是shell语法;因此,shell在向XMLStarlet提供查询之前删除了引号:

# bad: looks for @name=ident1, no quotes
# literal query is: count(/Result/Dataset[@name=ident1]/Row)
# ...which compares @name against the value of an element under Dataset named ident1
# ...since no such element exists, the result is a count of 0.
xmlstarlet sel -t -v 'count(/Result/Dataset[@name='ident1']/Row)' oscar.xml

取而代之的是:

# good: uses ""s on the outside, so ''s on the inside are literal
# literal query is: count(/Result/Dataset[@name='ident1']/Row)
xmlstarlet sel -t -v "count(/Result/Dataset[@name='ident1']/Row)" oscar.xml

...或者,如果你的shell是bash:

# good (but nonportable): uses $'' syntax, which makes \' produce a single literal '
# literal query is: count(/Result/Dataset[@name='ident1']/Row)
xmlstarlet sel -t -v $'count(/Result/Dataset[@name=\'ident1\']/Row)' oscar.xml

上述所有情况都是因为shell中的引号是每个字符的特征。例如,您可以写:

echo "$foo"'$bar'$baz

... $foo将根据双引号规则进行扩展(文字替换为注释),$bar将被视为文字字符串,$baz将被展开不带引号的扩展规则(使用字符串拆分和通配符导致不需要的行为)。