0

I have this command:

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 ^$

It does not work because the command version without variable (same value repeated instead of using $zgtag show results. What is wrong?

My investigation so far pointed out:

  • It has to be --var zgtag="'SuperTag'" because without single quotes the compiled XSLT by xmlstarlet would produce the following variable declaration: <xsl:variable select="SuperTag" name="zgtag"/> which is obviously wrong, the single quotes are missing!
  • In the XSLT compiled by xmlstarlet I can see that the variable is NOT inserted correctely, e.g. I see this:
<xsl:choose>
  <xsl:when test="//z:tag=''">

Then I used this version: --var zgtag="'SuperTag'" -m "/z:profile-extension" -i '//z:tag=$zgtag', now I get a correctly compiled XSLT debugging output of xmlstarlet:

  <xsl:template match="/">
    <xsl:variable select="'SuperTag'" name="zgtag"/>
    <xsl:for-each select="/z:profile-extension">
      <xsl:choose>
        <xsl:when test="//z:tag=$zgtag">

However the output still is empty, the same script without the variable (SuperTag directly inserted into the script multiple times) works just fine. So there must be still a problem with this var-styled command.

So any help welcome how to insert and use the defined variable correctly. The definition is not the problem, it's the usage of the variable in the xmlstarlet command.

10
  • 2
    Can you demonstrate the problem with a simplified command? What happens? What do you want to happen? Feb 7 at 9:59
  • Could you try with --var zgtag="'SuperTag'" and also remove the single quotes in the expression around $zgtag?
    – Kusalananda
    Feb 7 at 10:00
  • Is the issue that you're trying to use a shell variable inside the XML XPath? It's hard to tell without an example Feb 7 at 10:04
  • Oh, yes, what Chris said. You seem to be using double quotes around the expressions. You should be using single quotes, or escape the $. I didn't spot that due to the amount of text.
    – Kusalananda
    Feb 7 at 10:07
  • 1
    @basZero You still use double quotes around the expression. You can't do that without escaping the $ so that the shell does not think that $zgtag is a shell variable.
    – Kusalananda
    Feb 7 at 15:54

1 Answer 1

1

Let's take a simplified part of your expression (without the namespace, etc.)

xmlstarlet sel --var zgtag="SuperTag" -t -m "/profile-extension" -i "//tag='$zgtag'"

You've declared an XPath variable zgtag, referenced as $zgtag. However, you've put the expression //tag='$zgtag' inside double-quotes, so the shell can parse it. In doing so it evaluates variables, and it knows that as far as it is concerned, $zgtag is unset. So you get this:

xmlstarlet sel --var zgtag="SuperTag" -t -m "/profile-extension" -i "//tag=''"

The command is then executed - and obviously it doesn't do what you want.

The solution, as ever, is to use single quotes to protect the expression from the shell. (And remove the internal single quotes at the point of use, which are not expected by XPath)

xmlstarlet sel --var zgtag='"SuperTag"' -t -m "/profile-extension" -i '//tag=$zgtag'

In general, use single quotes for strings that do not need to be parsed by the shell, and double quotes otherwise. See What is the difference between the "...", '...', $'...', and $"..." quotes in the shell?


Worked example. I cannot test an application to your own command because I have neither valid input nor expected output for validating results. Instead I offer you this:

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
7
  • 1
    I'm thinking the variable should be an XML string, i.e. 'SuperTag', including the single quotes, and that the use of $zgtag should be without single quotes in the expression.
    – Kusalananda
    Feb 7 at 10:19
  • @Kusalananda no. Chris gave the good way AFAIK Feb 7 at 10:25
  • @Chris I tried out your version: --var zgtag="SuperTag" -t -m "/z:profile-extension" -i '//z:tag=$zgtag' -n -f, so I used double quotes for the variable definition and single quotes for the xpath expressions. I get this error: could not compile test expression '//z:tag='
    – basZero
    Feb 7 at 14:47
  • 1
    @chris-davis I added more info of my investigation into the question.
    – basZero
    Feb 7 at 15:07
  • @basZero got it. The variable definition must include quotes, but the use point must not. Answer modified to reflect this Feb 7 at 16:22

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .