0

I have this XML:

<results><testsuites><testcase name="XXXX (XXXXX)" time="20.3817"><result>success</result></testcase><total_time value="20.3830" /></testsuites></results>

I want to extract the 20.3817.

Trying some sed but not getting to work.

  • 2
    How would you like to do this? You tagged your Q sed, please include what you already tried. – Jan Feb 16 '16 at 17:04
  • Can you provide a second sample input and output? Just as one cannot extrapolate a line from a single data point, we cannot tell what you need from a single example. – jw013 Feb 16 '16 at 17:10
  • 2
    sed "s:/.*/20.3817/g" – MatthewRock Jul 28 '16 at 9:59
6

Don't use regular expressions to parse XML. Use an XML aware tool, e.g. xmllint:

xmllint --xpath 'string(/results/testsuites/testcase/@time)' file.xml
2

Use lxprintf:

lxprintf -e "%s\n" total_time/@value test.xml
  • When can I find this lxprintf command? (Either a link, or the relevant package name in a common distro will suffice.) Also, your answer looks like it will print "20.3830", not the OP's requested "20.3817". – JigglyNaga Jul 28 '16 at 11:42
2

With XMLStarlet:

$ xml sel -t -v '//testcase/@time' -nl data.xml
20.3817
1

perl has a nice XML parse in XML::Twig:

#!/usr/bin/env perl
use strict;
use warnings 'all'; 

use XML::Twig;

print XML::Twig -> parse ( \*DATA ) -> get_xpath('//total_time',0)->att('value');

__DATA__
<results><testsuites><testcase name="XXXX (XXXXX)" time="20.3817"><result>success</result></testcase><total_time value="20.3830" /></testsuites></results>

Or as a one liner:

perl -0777 -MXML::Twig -ne 'print XML::Twig -> parse (<>) -> get_xpath('//total_time',0)->att('value')'
0

You would be far, far better using an XML-aware tool

If it really is a simple case of extracting the value of the time attribute you can use sed. As you'll see from most of the answers here the better approach really is to use a tool that understands XML, but for really simple cases you might get away with using sed.

xml='<results><testsuites><testcase name="XXXX (XXXXX)" time="20.3817"><result>success</result></testcase><total_time value="20.3830" /></testsuites></results>'
echo "$xml" | sed -nr 's/.* time="([0-9.]+).*/\1/p'    # GNU
28.3817
echo "$xml" | sed -n 's/.* time="\([0-9.]*\).*/\1/p'   # Non-GNU
28.3817

Or grep

echo "$xml" | grep -Po '(?<=time=")([0-9.]+)'          # GNU
20.3817

But I'd still prefer something XML-aware like xmlstarlet, which can recognise time as an attribute of <testcase>.

  • Sorry, I'm afraid I wouldn't even suggest using sed, for all the reasons I wouldn't suggest trying to put a screw in the wall with a hammer. Whilst it might technically work, it will always be a bodge and produce messy, if technically functional solutions. – Sobrique Jul 28 '16 at 11:00
  • @Sobrique I'm with you. However, it is possible the OP is running on a system that doesn't have (cannot have) a sensible way of parsing the XML. So for them, or for a potential future reader in that position, I'd like to offer the sed and grep options. I think I've added enough caveats to the suggestions (although I suppose I ought to rewrite the sed to avoid the GNU extensions...). – roaima Jul 28 '16 at 11:09

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.