Search code examples
xmlbatch-processingxmlstarlet

XMLStarlet namespace issue/can't extract node value from XML


I'm trying to assign a tag value from an XML file to a variable using a batch file and xmlstarlet (version 1.6.1). The XML file has a namespace and by defining the namespace in the xmlstarlet command I receive two errors.

The XML file (myApp-app.xml) looks like this:

<?xml version="1.0" encoding="utf-8" standalone="no"?>
<application xmlns="http://ns.adobe.com/air/application/17.0">
    <!-- A string value of the format <0-999>.<0-999>.<0-999> that represents application version which can be used to check for application upgrade. 
    Values can also be 1-part or 2-part. It is not necessary to have a 3-part value.
    An updated version of application must have a versionNumber value higher than the previous version. Required for namespace >= 2.5 . -->
    <versionNumber>1.0.0</versionNumber>
</application>

This is the batch file:

@ECHO OFF
FOR /F %%i IN ('XML.EXE sel -t -c -N x="http://ns.adobe.com/air/application/17.0" "//x:versionNumber" "myApp-app.xml"') DO SET version=%%i
ECHO Version is %version%

(I also tried to use "//x:application/versionNumber" instead of "//x:versionNumber")

The error I receive is:

failed to load external entity "x"
Attempt to load network entity http://ns.adobe.com/air/application/17.0
failed to load external entity "/x:application/filename"
Version is NaN

I tried changing the order of arguments but this results in either completely broken command or the error message "Bad namespace option: namespace should have the form <prefix>=<url>", whereas I always made sure that the namespace definition x="http://ns.adobe.com/air/application/17.0" is stated behind -N.

Can anyone see what may cause the errors and why it is not working?


Solution

  • The -N x=http... options must go first just after the sel. Outside of the FOR construct, this works

    XMLSTARLET.EXE sel -N x=http://ns.adobe.com/air/application/17.0 -t -c //x:versionNumber myApp-app.xml
    

    but it gives <versionNumber xmlns="http://ns.adobe.com/air/application/17.0">1.0.0</versionNumber>. I think you were after just 1.0.0, so you should change the -c (--copy-of) to -v (--value-of).

    XMLSTARLET.EXE sel -N x=http://ns.adobe.com/air/application/17.0 -T -t -v //x:versionNumber myApp-app.xml
    

    -T is short for --text (as opposed to the default XML output).


    Inside the FOR construct, the = needs to be quoted, the following all work:

    FOR /F %%i IN ('XMLSTARLET.EXE sel -N "x=http://ns.adobe.com/air/application/17.0" -T -t -v //x:versionNumber myApp-app.xml') DO SET version=%%i
    FOR /F %%i IN ('XMLSTARLET.EXE sel -N x"="http://ns.adobe.com/air/application/17.0 -T -t -v //x:versionNumber myApp-app.xml') DO SET version=%%i
    FOR /F %%i IN ('XMLSTARLET.EXE sel -N x^=http://ns.adobe.com/air/application/17.0  -T -t -v //x:versionNumber myApp-app.xml') DO SET version=%%i