Extract Element from XML file

<?xml version = '1.0' encoding = 'utf-8'?><Data><Request><output_option>PCL</output_option><slip_page_indicator>N</slip_page_indicator><corspd_id>0003958228</corspd_id><eff_dt>2015-05-20</eff_dt><pgm_typ_cd>FS</pgm_typ_cd><csld_num></csld_num><off_id>000000</off_id><actn_cd>T</actn_cd><cpy_qty>01</cpy_qty><Reason_Codes><Reason_Code>FAS701</Reason_Code></Reason_Codes><Mailing_Addresses><adr_cnt>01</adr_cnt><Mailing_Address><sort_info>954076262Elsa628CF123f3343</sort_info><addresee1>Narah Ornbaun</addresee1><addresee2></addresee2><street_adr1>628 Elsa DR</street_adr1><street_adr2/><city>Santa Jose</city><state>CA</state><zip>95407-6262</zip><postnet>*954076262289*</postnet><email>N</email><hrdcpy>Y</hrdcpy></Mailing_Address></Mailing_Addresses><Document><doc_name>ALL_NOA_NO_Budget_Master_Document</doc_name><language>EN</language><corspd_num>CDS 66S-0 (4/00)</corspd_num> 

Out of this XML file I want to extract the content between the XML element <corspd_num>.

I just tried with the sed command , as the following. But it doesn't work.

 sed -n 's:.*<corspd_num>\(.*\)</corspd_num>.*:\1:p' DRIVER_TagString

Hello Siva_SQL,

Could you please try following and let me know if this helps.

 awk '{match($0,/<corspd_num>.*<\/corspd_num>/);print substr($0,RSTART+12,RLENGTH-25)}'  Input_file
 

Thanks,
R. Singh

Getting error as;

awk: Input line <?xml version = '1.0 cannot be longer than 3,000 bytes.
The source line number is 1.

Is that possible using sed ?

Your approach seems to work for me. What exactly does not satisfy you?

[akshay@localhost tmp]$ grep -oP '(?<=<corspd_num>).*(?=</corspd_num>)' file
CDS 66S-0 (4/00)

On systems that limit line lengths in sed and awk , the following awk script should still work as long as the data in the field you want to print does not contain a greater than character ( > ):

awk -F'</corspd_num' -v RS='>' 'NF > 1{print $1}' DRIVER_TagString

but, if this is a Solaris/SunOS system, change awk to /usr/xpg4/bin/awk .

Don Cragun,

It would be much helpful, if you can explain the command as what it does in detail. Since being newbie I finding it difficult to understand the commands used.

Hi.

Using commonly available utilities (input was formatted with xmllint, q.v.):

#!/usr/bin/env bash

# @(#) s1	Demonstrate extraction from XML file, xml_grep, xgrep.
# xml_grep: part of xml-twig-tools package, q.v.
# xgrep: http://wohlberg.net/public/software/xml/xgrep/

# Utility functions: print-as-echo, print-line-with-visual-space, debug.
# export PATH="/usr/local/bin:/usr/bin:/bin"
LC_ALL=C ; LANG=C ; export LC_ALL LANG
pe() { for _i;do printf "%s" "$_i";done; printf "\n"; }
pl() { pe;pe "-----" ;pe "$*"; }
db() { ( printf " db, ";for _i;do printf "%s" "$_i";done;printf "\n" ) >&2 ; }
db() { : ; }
C=$HOME/bin/context && [ -f $C ] && $C xgrep xml_grep

FILE=${1-data1}

pl " Input data file $FILE:"
cat $FILE

pl " Results, xgrep:"
xgrep -t -s "Document:corspd_num/.*/" $FILE

pl " Results, xml_grep:"
xml_grep -t "corspd_num" $FILE

exit 0

producing:

$ ./s1

Environment: LC_ALL = C, LANG = C
(Versions displayed with local utility "version")
OS, ker|rel, machine: Linux, 2.6.26-2-amd64, x86_64
Distribution        : Debian 5.0.8 (lenny, workstation) 
bash GNU bash 3.2.39
xgrep 0.08 (libxml2,pcre)
xml_grep /usr/bin/xml_grep version 0.7

-----
 Input data file data1:
<?xml version="1.0" encoding="utf-8"?>
<Data>
  <Request>
    <output_option>PCL</output_option>
    <slip_page_indicator>N</slip_page_indicator>
    <corspd_id>0003958228</corspd_id>
    <eff_dt>2015-05-20</eff_dt>
    <pgm_typ_cd>FS</pgm_typ_cd>
    <csld_num/>
    <off_id>000000</off_id>
    <actn_cd>T</actn_cd>
    <cpy_qty>01</cpy_qty>
    <Reason_Codes>
      <Reason_Code>FAS701</Reason_Code>
    </Reason_Codes>
    <Mailing_Addresses>
      <adr_cnt>01</adr_cnt>
      <Mailing_Address>
        <sort_info>954076262Elsa628CF123f3343</sort_info>
        <addresee1>Narah Ornbaun</addresee1>
        <addresee2/>
        <street_adr1>628 Elsa DR</street_adr1>
        <street_adr2/>
        <city>Santa Jose</city>
        <state>CA</state>
        <zip>95407-6262</zip>
        <postnet>*954076262289*</postnet>
        <email>N</email>
        <hrdcpy>Y</hrdcpy>
      </Mailing_Address>
    </Mailing_Addresses>
    <Document><doc_name>ALL_NOA_NO_Budget_Master_Document</doc_name><language>EN</language><corspd_num>CDS 66S-0 (4/00)</corspd_num>

</Document>
  </Request>
</Data>

-----
 Results, xgrep:
<Document><doc_name>ALL_NOA_NO_Budget_Master_Document</doc_name><language>EN</language><corspd_num>CDS 66S-0 (4/00)</corspd_num>  </Document>

-----
 Results, xml_grep:
CDS 66S-0 (4/00)

Best wishes ... cheers, drl

Since, most UNIX text processing utilities on some systems have line length limitations of approximately 2048 bytes per line (and you have told us that your system has a limit of 3000 bytes per line in sed ), we have to assume that you can't process this input file in the normal ways. Although, it is very confusing for you to give us an 881 byte file and tell us that utilities are complaining because it contains a line that is longer than 3000 bytes???

We can get around awk 's line length limitations by setting a record separator that will select records that are shorter than its line length limit. With your sample xml file we can use the > as the record separator and get lots of short records instead of a single 3000+ byte long line.

With the data you're trying to capture being of the form:

...<corspd_num>data</corspd_num>...

the text shown in red will be in previous records or following records. By setting the field separator to the string </corspd_num , any record that has two fields with have the data that you want as the 1st field in that record and an empty field as the 2nd field on that line. Any record that does not contain the field separator string will either have zero fields or one field. So the code:

awk -F'</corspd_num' -v RS='>' 'NF > 1{print $1}' DRIVER_TagString
  1. invokes awk
  2. with the input field separator set to </corspd_num (specified by -F'</corspd_num' ),
  3. the input record separator set to > (specified by -v RS='>' ),
  4. the script to be evaluated set to 'NF > 1{print $1}' , and
  5. the file to be processed specified by DRIVER_TagString .

And the script NF > 1{print $1} says that for each record found in the input file, if the number of fields found in that record ( NF ) is more than 1 ( NF > 1 ) then print ( print ) the 1st field from that record ( $1 ). Other records in the file are skipped over without printing anything.