0

I want to grep tag value of and if its 01 it must print another tag and along with its value .

Sample XML file :

<CustName>Unix</CustName>
<CustomerId>999</CustomerId>
<dept>developer</dept>
<account>01</account>

Desired output :

If value of account is 01 it must print the below along with total count of occurance of 01 value in account tag:

<CustName>Unix</CustName>
<CustomerId>999</CustomerId>
<account>01</account>

count :1

What i have tried :

grep -oP '(?<=<<c>account>).*(?=<<c>/account)' cust.xml

01

grep -C 10 -oP '(?<=<<c>account>).*(?=<<c>/account)' cust.xml

-C 10 will print 10 line above and below but it did not work .

  • 1
    please be careful with XML – Jeff Schaller Jul 19 '16 at 14:42
  • @JeffSchaller may i know what is wrong with the question ? – star Jul 19 '16 at 14:54
  • When working with XML, you should use proper XML libraries, not grep and "hope for the best". Simple regex pattern matching is not sufficient. Almost all current scripting languages have XML libraries which are easy enough. – Hans-Martin Mosner Jul 19 '16 at 15:28
  • 2
    Use xmlstarlet for this. – Mark Plotnick Jul 19 '16 at 17:11
  • If you can ensure the specific xml-format to be a stricter subset ("Tags close on the same line as they open", "Values don't contain newlines), you can get away with some super simple awk. – Alex Stragies Jul 19 '16 at 18:34
0

Don't use grep or regular expressions in general. It's a very bad choice for working with XML, because XML is contextual and regular expressions are not. You will never get a solution that isn't brittle.

However, other options exist. Personally - I like perl. I have modified your XML a little too I'm afraid, because what you've posted isn't valid. You NEED a root tag, if nothing else.

However something like this will do what you want:

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

use XML::Twig;

#parse from 'data' block below. You probably want 'parsefile'. 
my $twig = XML::Twig -> parse ( \*DATA ); 
#set output formatting - one of the reasons why regex is prone to fail. 
$twig -> set_pretty_print ('indented_a');

#XPATH is _like_ regex, but for xml. 
#So in the below - we find 'acc' nodes, with an account with a string value of '01'. 
#And then print it.

foreach my $acc ( $twig -> get_xpath('//acc/account[string()="01"]/..' )) {
   $acc -> print;
}


#doing this a slightly different way - you could just increment the count
#in the above loop though
my $count = scalar $twig -> get_xpath('//account[string()="01"]');
print "\nNumber of matches: $count\n";

__DATA__
<root>
  <acc>
     <CustName>Unix</CustName>
     <CustomerId>999</CustomerId>
     <dept>developer</dept>
     <account>01</account>
  </acc>
  <acc>
     <CustName>Windows</CustName>
     <CustomerId>666</CustomerId>
     <dept>developer</dept>
     <account>02</account>
  </acc>
</root>

Give us a more complete XML sample, and a desired output, and we can put together something more accurate for what you're trying to do.

But please - don't use regular expressions, they simply cannot handle XML properly. It's like using a hammer to put a screw in the wall - it sort of works, but it'll never be anything other than messy.... and screwdrivers are readily available.

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.