我有这个命令:
find . -iname '*.xml' | xargs xmlstarlet sel -N z="http://abc.com/article/1.0/" \\
--var zgtag="SuperTag" -t -m "/z:profile-extension" -i "//z:tag='$zgtag'" \\
-n -f -o "," -v "count(//z:zgContextsAnonymTotal[z:tag='$zgtag'])" -o "," \\
-v "//z:zgContextsAnonymTotal/z:tag[.='$zgtag']/@z:timestamp" -o "," \\
-v "count(//z:zgContextsREGTotal[z:tag='$zgtag'])" -o "," \\
-v "//z:zgContextsREGTotal/z:tag[.='$zgtag']/@z:timestamp" -o "," \\
-v "count(//z:zgContextsPremiumTotal[z:tag='$zgtag'])" -o "," \\
-v "//z:zgContextsPremiumTotal/z:tag[.='$zgtag']/@z:timestamp" | grep -v ^$
它不起作用,因为命令版本没有变量(重复相同的值而不是使用$zgtag
显示结果。出了什么问题?
到目前为止我的调查表明:
- 一定是
--var zgtag="'SuperTag'"
因为没有单引号,xmlstarlet 编译的 XSLT 会产生以下变量声明:<xsl:variable select="SuperTag" name="zgtag"/>
这显然是错误的,单引号丢失了! - 在 xmlstarlet 编译的 XSLT 中,我可以看到变量未正确插入,例如我看到:
<xsl:choose>
<xsl:when test="//z:tag=''">
然后我使用了这个版本:--var zgtag="'SuperTag'" -m "/z:profile-extension" -i '//z:tag=$zgtag'
,现在我得到了正确编译的 xmlstarlet 的 XSLT 调试输出:
<xsl:template match="/">
<xsl:variable select="'SuperTag'" name="zgtag"/>
<xsl:for-each select="/z:profile-extension">
<xsl:choose>
<xsl:when test="//z:tag=$zgtag">
然而输出仍然是空的,没有变量的相同脚本(SuperTag
直接插入脚本多次)工作得很好。所以这个var风格的命令肯定还有问题。
因此,任何帮助都欢迎如何正确插入和使用定义的变量。定义不是问题,问题在于 xmlstarlet 命令中变量的使用。
答案1
让我们看一下表达式的简化部分(没有命名空间等)
xmlstarlet sel --var zgtag="SuperTag" -t -m "/profile-extension" -i "//tag='$zgtag'"
您已经声明了一个 XPath 变量zgtag
,引用为$zgtag
。但是,您已将表达式放在//tag='$zgtag'
双引号内,以便 shell 可以解析它。在此过程中,它会评估变量,并且它知道就其而言,变量$zgtag
尚未设置。所以你得到这个:
xmlstarlet sel --var zgtag="SuperTag" -t -m "/profile-extension" -i "//tag=''"
然后执行该命令 - 显然它没有执行您想要的操作。
与以往一样,解决方案是使用单引号来保护表达式免受 shell 的影响。 (并在使用时删除内部单引号,这是 XPath 所不希望的)
xmlstarlet sel --var zgtag='"SuperTag"' -t -m "/profile-extension" -i '//tag=$zgtag'
一般来说,不需要由 shell 解析的字符串使用单引号,否则使用双引号。看shell 中的 "..."、'...'、$'...' 和 $"..." 引号之间有什么区别?
工作过的例子。我无法根据您自己的命令测试应用程序,因为我既没有有效的输入,也没有用于验证结果的预期输出。相反,我向您提供这个:
cat >xml <<'EOF'
<?xml version="1.0"?>
<outer>
<inner x="a">Element A text</inner>
<inner x="b">Element B text</inner>
</outer>
EOF
xmlstarlet sel -t --var e='"b"' -v '//inner[@x=$e]' -n <xml
Element B text