How to extract particular value from xml file and

2019-09-19 23:36发布

问题:

Here is the xml code where I want to extract 'string' value macromedia.jdbc.MacromediaDriver and modify it as NoDatabase using perl.

File name- neo-datasource.xml

<?xml version="1.0"?>
-<wddxPacket version="1.0">
   <header/>
     -<data>
        -<array length="2">
          -<struct type="coldfusion.server.ConfigMap">
             -<var name="CFASTSTJ">
                -<struct type="coldfusion.server.ConfigMap">
                   -<var name="alter">
                      <boolean value="true"/>
                    </var>
                   -<var name="CLASS">
                       <string>macromedia.jdbc.MacromediaDriver</string>
                    </var>
                 </struct>
           </struct>
         </array>
       </data>      
</wddxpacket>   

Please anyone can share your ideas or perl script.

回答1:

It's easy enough using an XML Parser. Like XML::Twig.

For example:

#!/usr/bin/perl;
use strict;
use warnings;

use XML::Twig;

XML::Twig->new(
    'pretty_print'  => 'indented_a',
    'twig_handlers' => {
        'var[@name="CLASS"]/string' => sub { $_->set_text('NoDatabase') }
    }
)->parse( \*DATA )->print;

__DATA__
<?xml version="1.0"?>
<wddxPacket version="1.0">
   <header/>
     <data>
        <array length="2">
          <struct type="coldfusion.server.ConfigMap">
             <var name="CFASTSTJ">
                <struct type="coldfusion.server.ConfigMap">
                   <var name="alter">
                      <boolean value="true"/>
                    </var>
                   <var name="CLASS">
                       <string>macromedia.jdbc.MacromediaDriver</string>
                    </var>
                 </struct>
              </var>
           </struct>
         </array>
       </data>  
</wddxPacket>   

This uses an xpath expression 'var[@name="CLASS"]/string' - which means any element var with a name attribute equal to CLASS with a subelement string. It will apply this to any instance that matches this. You may need a more specific xpath for your data. (e.g. data/array/struct[@type="coldfusion.server.ConfigMap"]/var[@name="CFASTSTJ"]/struct[@type="coldfusion.server.ConfigMap"]/var[@name="CLASS"]/string - that's probably overkill though :))

Note - I've fixed your XML - I'm assuming that's a typographic error, rather than broken source XML. If your source XML is broken, then you have bigger problems.

This outputs:

<?xml version="1.0"?>
<wddxPacket version="1.0">
  <header/>
  <data>
    <array length="2">
      <struct type="coldfusion.server.ConfigMap">
        <var name="CFASTSTJ">
          <struct type="coldfusion.server.ConfigMap">
            <var name="alter">
              <boolean value="true" />
            </var>
            <var name="CLASS">
              <string>NoDatabase</string>
            </var>
          </struct>
        </var>
      </struct>
    </array>
  </data>
</wddxPacket>


回答2:

This program uses the XML::Twig module to process your data

use strict;
use warnings;

use XML::Twig;

my $twig = XML::Twig->new( keep_spaces => 1 );
$twig->parsefile('neo-datasource.xml');

my ($class_string) = $twig->findnodes('//var[@name="CLASS"]/string');
$class_string->set_text('NoDatabase');

print $twig->toString;

output

<?xml version="1.0"?>
<wddxPacket version="1.0">
  <header/>
  <data>
    <array length="2">
      <struct type="coldfusion.server.ConfigMap">
        <var name="CFASTSTJ">
          <struct type="coldfusion.server.ConfigMap">
            <var name="alter">
              <boolean value="true"/>
            </var>
            <var name="CLASS">
              <string>NoDatabase</string>
            </var>
          </struct>
        </var>
      </struct>
    </array>
  </data>
</wddxPacket>