0

I'm new to XML files and am trying to get out some values using XPath. I will plot this values in Jenkins using the Plot plugin. This takes the element names on the x-axis and the element value on the y-axis.

My xml file looks like:

<?xml version="1.0" encoding="UTF-8" ?>
<foo>
    <file file_name="file1.c">
        <metrics>
            <metric id="M1">15</metric>
            <metric id="M2">7</metric>
            <metric id="M3">9</metric>
        </metrics>
    </file>
    <file file_name="file2.c">
        <metrics>
            <metric id="M1">1110</metric>
            <metric id="M2">56</metric>
            <metric id="M3">1</metric>
        </metrics>
    </file>
</foo>

I want to plot M1 for all file_name, therefore what I need to get back using XPath is a nodelist like

<file1.c>15</file1.c>
<file2.c>1110</file1.c>

I tried

//file/metrics/*[@id='M1']

but so I get

<metric id="M1">15</metric>
<metric id="M1">15</metric>

I found some similar questions, but couldn't adapt it to my case: This for example gets back the parent element including all children.

How can I achieve what I need?

Community
  • 1
  • 1
S. Inder
  • 77
  • 1
  • 9

1 Answers1

0

XPath can't create new elements on its own. You have to use XQuery or an XSLT transformation or a home-made parsing using a combination of DOM and XPath in the language of your choice. XPath 2.0 could be of some help but I guess you're limited to XPath 1.0.

BTW I would add some context to your XPath expression instead of using * :

//file/metrics/metric[@id='M1']

With XPath 2.0 alone, you could do this :

string-join(//file/(@file_name,metrics/metric[@id='M1']/text()),',')

And get a string with the data you need :

file1.c,15,file2.c,1110

It is more powerful than XPath 1.

With XQuery 1.0, you could write :

<document_element>
{
  for $f in //file
  return element { $f/@file_name } { $f/metrics/metric[@id='M1']/text() }
}
</document_element>

And get the answer you want :

<?xml version="1.0" encoding="UTF-8"?>
<document_element>
   <file1.c>15</file1.c>
   <file2.c>1110</file2.c>
</document_element>

We use a computed element constructor element { ... } { ... }to dynamically create a new element whose name is based on some value in the file. XQuery is really powerful and convenient to use.

Ludovic Kuty
  • 4,868
  • 3
  • 28
  • 42
  • Thank you, using XQuery would work for sure. Since I have no experience with that I prefered to export this file in csv (instead of xml), edit it and plot the data from the resulting file. – S. Inder Dec 04 '15 at 12:21
  • Thank you for the edit. Unfortunately I'm limited to XPath 1. – S. Inder Dec 09 '15 at 12:02
  • 1
    I have tested the solution using XQuery and it works well. For all those who aren't familiar with XQuery this is how I did it: first I installed [xmlsh](http://www.xmlsh.org/HomePage), then I saved the code proposed by Ikuty as `create_report.xquery` Then run `xmlsh` and `xquery -i my_file.xml -f create_report.xquery > report.xml` from command line, where `my_file.xml` is my initial file and `report.xml` will be the output file. – S. Inder Dec 09 '15 at 12:12
  • Didn't know about `xmlsh`. It is interesting – Ludovic Kuty Dec 09 '15 at 15:50