xmlyqxq

`yq` seems cannot work with XML with just one element


I am using the following the command to extract data from an XML file:

yq -p=xml '.resources.string[] | [.+@name, .+content] | join("|")' sample.xml

With an input XML file like:

<resources>
    <string name="String-1">String 1</string>
    <string name="String-2">String 2</string>
</resource>

The command works fine with the output:

String-1|String 1
String-2|String 2

But if the input XML file contains only one element:

<resources>
    <string name="String-1">String 1</string>
</resource>

The output is just two empty lines.

The input file is read properly and one element, with one attribute and one content, is properly identified, but somehow the values are dropped. If not doing the join operation with the same one element input XML file:

yq -p=xml '.resources.string[] | [.+@name, .+content] ' input.xml 

The output is:

[]
[]

It looks like a bug but it could also be some settings I missed. Any workaround or fix?

I am using yq version v4.34.2 installed with brew on MacOS (Intel) 13.4.1


Solution

  • The problem here is that in your second example, yq treats resources.string as a dictionary rather than an array. Compare the output of yq -pxml .resources between the first example:

    string:
      - +content: String 1
        +@name: String-1
      - +content: String 2
        +@name: String-2
    

    And the second example:

    string:
      +content: String 2
      +@name: String-2
    

    So for your second example, you can ask for:

    $ yyq -pxml -oyml '.resources.string|[.+@name, .+content]|join("|")' < sample2.xml
    String-2|String 2
    

    The second example is treated like a dictionary because that's how yq handles an element with distinct child elements, like:

    <cat>
      <says>meow</says>
      <legs>4</legs>
      <cute>true</cute>
    </cat>
    

    Which becomes:

    cat:
      says: meow
      legs: "4"
      cute: "true"
    

    Looking through the docs there doesn't appear to be a way to enforce the array interpretation when there's a single element.