Search code examples
xmldynamictagselementxmlstarlet

Using xmlstarlet to pattern match element tags


I am trying to determine how to use xmlstarlet to get the xml tag and values when the tag elements aren't constant.

for example,

Input file:

<?xml version="1.0" encoding="us-ascii"?>
<ST>
  <Data3020>
    <value>110</value>
    <detailType>N/A</detailType>
  </Data3020>
  <Data3030>
    <value>10</value>
    <detailType>N/A</detailType>
  </Data3030>
  <Data3040>
    <value>70</value>
    <detailType>N/A</detailType>
  </Data3040>
  <Data3080>
    <value>770</value>
    <detailType>N/A</detailType>
  </Data3080>
  <Data3090>
    <value>44</value>
    <detailType>N/A</detailType>
  </Data3090>
</ST>

Expected Output:

BoxName|value|detailType|
Data3020|100|N/A|
Data3030|10|N/A|
Data3030|70|N/A|
Data3040|770|N/A|
Data3050|44|N/A|

I tried the following to get the tag name and the values separately but I can't figure out how to combine them

xmlstarlet sel -t -m "/ST/*" -v "name()" -nl test.xml
Data3020
Data3030
Data3040
Data3080
Data3090
xmlstarlet sel --template --value-of "//ST" test.xml


110
N/A


10
N/A


70
N/A


770
N/A


44
N/A

Solution

  • With :

    xidel --xquery '
        for $n in /ST/*
            let $name := $n/name()
            let $val  := $n/value
            let $type := $n/detailType
        return concat($name, "|", $val, "|", $type, "|")
    ' file
    

    Or re-using the XPath @Yitzhak Khabinsky given in comments:

    xidel -e '/ST/*/concat(name(),"|", value, "|", detailType)' file
    

    or with saxon-lint (my own project):

    saxon-lint --xpath '/ST/*/concat(name(),"|", value, "|", detailType)' file
    

    Or with via the comment of @Cyrus:

    xmlstarlet sel -t -m '/ST/*' \
        -v "concat(name(),'|',value,'|',detailType,'|')" \
        -n file
    
    Data3020|110|N/A|
    Data3030|10|N/A|
    Data3040|70|N/A|
    Data3080|770|N/A|
    Data3090|44|N/A|