Search code examples
xmllinuxbashxpathxmllint

xmllint - unable to read special characters


On the bash shell prompt i want to run xmllint to get data from a xml file. Lets look at a file in which i have no issues:

behold the fruits.xml file:

      <?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<map>
  <string name="mykey">grapes</string>
</map>

and this is me using xmllint to get the value "grapes" from fruits.xml

xmllint --xpath "string(/map/string[@name = 'mykey'])" fruits.xml

and i get the output of the following:

$ grapes

great i got the value, but this is not the actual key i need to use. "mykey" should be "c1:fruits_id-%1$s"

now when i change the "mykey" value in the fruits.xml file to another value i am unable to get any return value from xmllint:

<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<map>
  <string name="c1:fruits_id-%1$s">grapes</string>
</map>


xmllint --xpath "string(/map/string[@name = 'c1:fruits_id-%1$s'])" fruits.xml

the above command returns nothing. All im doing is changing the key name and now it wont work. can someone help ?


Solution

  • (The XML document you show does not have the c1: in front of the attribute value - a typo, I guess?)

    If you use $ in a shell command, it is interpreted as a variable and variable interpolation kicks in. Because the variable does not exist, it is replaced with nothing. You can test this by changing your XML document to

    <?xml version='1.0' encoding='utf-8' standalone='yes' ?>
    <map>
      <string name="c1:fruits_id-%1">grapes</string>
    </map>
    

    The only change is that the two characters $s are deleted. Now the path expression finds the string:

    $ xmllint --xpath "string(/map/string[@name = 'c1:fruits_id-%1$s'])" fruit.xml
    grapes
    

    Either escape the character as \$ as Biffen has already suggested:

    $ xmllint --xpath "string(/map/string[@name = 'c1:fruits_id-%1\$s'])" fruit.xml
    grapes
    

    or, equally easy, swap the quotes:

    $ xmllint --xpath 'string(/map/string[@name = "c1:fruits_id-%1$s"])' fruit.xml
    grapes
    

    There is no variable interpolation for strings that are delimited by single quotes, even if there are double quotes inside them (see this question).