如何使用Perl在XML中查找和替换文本?

时间:2010-01-12 20:39:04

标签: xml perl replace find

我的XML文件看起来像这样:

<doc>
    <RU1>
       <conf> 
              <prop name="a" val="http://a.org/a.html> 
       </conf>    
    </RU1>
    <RAU1>
     <conf> 
              <prop name="a" val="http://a.org/a.html> 
       </conf>
    </RAU1>
    <RU2>
     <conf> 
              <prop name="a" val="http://a.org/a.html> 
       </conf>
    </RU2>
</doc>

我想在prop字段的值中替换“a.org”,在perl中以RU开头的所有父标记下,用“b.com”替换。如何将更改作为xml文件获取?< / p>

3 个答案:

答案 0 :(得分:8)

假设您的XML格式正确(事实并非如此),您可以使用a number of CPAN modules来完成工作。大多数将涉及解析文档,使用XPath查询找到您的位,并再次打印文档。

以下是XML :: Twig的示例。我不得不修复XML以使其解析。

#!/usr/bin/perl

use strict;
use warnings;

use XML::Twig;

my $twig = XML::Twig->new(
    twig_handlers => {
        'conf/prop' => sub { $_->{att}{val} =~ s/a.org/b.org/; }
    },
    pretty_print => "indented"
);
$twig->parse(join "", <DATA>);

$twig->print;


__END__
<foo>
<RU1>
   <conf>
          <prop name="a" val="http://a.org/a.html" />
   </conf>
</RU1>
<RAU1>
   <conf>
          <prop name="a" val="http://a.org/a.html" />
   </conf>
</RAU1>
<RU2>
 <conf> 
          <prop name="a" val="http://a.org/a.html" />
   </conf>
</RU2>
</foo>

答案 1 :(得分:4)

从CPAN中获取XML解析器并使用它。他们是有原因的。

一旦你完成了它,它就是一些相当简单的XPath表达式来获取你想要的节点,然后在特定属性本身上进行一些快速文本替换。

答案 2 :(得分:3)

使用以下样式表

<?xml version="1.0"?>

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:template match="node()|@*">
    <xsl:copy>
      <xsl:apply-templates select="@*"/>
      <xsl:apply-templates/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="//*[starts-with(local-name(), 'RU')]//prop/@val">
    <xsl:call-template name="replace-aorg" />
  </xsl:template>

  <xsl:template name="replace-aorg">
    <xsl:param name="text" select="." />
    <xsl:choose>
      <xsl:when test="contains($text, 'a.org')">
        <xsl:value-of select="substring-before($text, 'a.org')"/>
        <xsl:text>b.com</xsl:text>
        <xsl:call-template name="replace-aorg">
          <xsl:with-param name="text" select="substring-after($text, 'a.org')"/>
        </xsl:call-template>
      </xsl:when>
      <xsl:otherwise>
        <xsl:value-of select="$text"/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>
</xsl:stylesheet>

并将XML文档调整为

<doc>
<RU1>
   <conf> 
          <prop name="a" val="http://a.org/a.html" /> 
   </conf>    
</RU1>
<RAU1>
 <conf> 
          <prop name="a" val="http://a.org/a.html" /> 
   </conf>
</RAU1>
<RU2>
 <conf> 
          <prop name="a" val="http://a.org/a.html" /> 
   </conf>
</RU2>
</doc>

输出:

$ xsltproc sty.xml doc.xml
<?xml version="1.0"?>
<doc>
<RU1>
   <conf>
          <prop name="a">http://b.com/a.html</prop>
   </conf>
</RU1>
<RAU1>
 <conf>
          <prop name="a" val="http://a.org/a.html"/>
   </conf>
</RAU1>
<RU2>
 <conf>
          <prop name="a">http://b.com/a.html</prop>
   </conf>
</RU2>
</doc>

所以从Perl开始,就像

那样
system("xsltproc", "style.xsl", "doc.xml") == 0
  or warn "$0: xsltproc exited " . ($? >> 8);