0

I have an xml document of the form

root
 +- foo
 +- bar
 |   +- @baz

I want to extract the value of /root/foo and of /root/bar/@baz in one go from the command line.

I can do

cat file.xml | xmlstarlet sel -t -v "/root/foo" -n

and

cat file.xml | xmlstarlet sel -t -v "/root/bar/@baz" -n

separately.

And I can do

cat file.xml | xmlstarlet sel -t -v "/root/foo|bar/@baz" -n

which gives me the value of baz if foo doesn't exist.

I tried

cat file.xml | xmlstarlet sel -t -v "/root/[foo and bar/@baz]" -n

but that doesn't work

compilation error: element with-param
XSLT-with-param: Failed to compile select expression '/root/[foo and bar/@baz]'

How can I get both?

Update: Minimum reproducible example

XML File

<root>
  <foo>Value F1</foo>
  <bar baz="Value B1" />

  <foo>Value F2</foo>
  <bar baz="Value B2" />
</root>

The command

cat file.xml | xmlstarlet sel -t -v "/root/foo" -n

Gives me

Value F1
Value F2

and

cat file.xml | xmlstarlet sel -t -v "/root/bar/@baz" -n

Gives me

Value B1
Value B2

and

cat file.xml | xmlstarlet sel -t -v "/root/foo|bar/@baz" -n

Also gives me

Value F1
Value F2

My expected outcome is something like

Value F1 Value B1
Value F2 Value B2

each in one line.

I am using xmlstarlet, version

1.6.1
compiled against libxml2 2.9.13, linked with 20913
compiled against libxslt 1.1.35, linked with 10135

I don't care which version of XPath I need to use to get this outcome.

2
  • 1
    While asking an XPath question you need to provide a minimal reproducible example: (1) Well-formed input XML. (2) Your logic, and XPath expression that tries to implement it. (3) Desired output based on the #1 above. (4) XPath processor and its conformance with the XPath standards: 1.0, 2.0, 3.0, 3.1, or 4.0. Commented Jan 30, 2024 at 15:27
  • You say "I don't care which version of XPath I need to use to get this outcome." But xmlstarlet restricts you to 1.0. If you switched to Saxon's Gizmo [my company's product] you could use XPath 3.1, or even 4.0 if you don't mind being on the bleeding edge. Commented Jan 30, 2024 at 18:31

2 Answers 2

1

You were almost there with:

/root/foo|bar/@baz

try this:

root/foo|/root/bar/@baz
Sign up to request clarification or add additional context in comments.

Comments

-1
xmlstarlet sel -t -v /root/foo[1] -o " " -v /root/bar[1]/@baz -n -v /root/foo[2] -o " " -v /root/bar[2]/@baz -n file.xml

output:

Value F1 Value B1
Value F2 Value B2

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.