XMLStarlet 在 XPath 表达式中使用变量

XMLStarlet 在 XPath 表达式中使用变量

我有这个命令:

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

相关内容