2010-01-12 53 views
2

我的XML文件看起来是这样的:如何使用Perl查找和替换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> 

我想在道具字段的值来代替“a.org”,其下具有RU在Perl启动所有父标签,以“b.com “。我如何获得更改为一个XML文件?

+6

您的XML格式错误。值缺少引号,并且prop标签未关闭。这是一个错误,还是你想解析格式不正确的XML? – Schwern

回答

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> 
+0

我同意你的回答,但应该注意的是,涉及解析,替换和序列化的每一个操作都会丢失东西:实体被扩展,空白可以被重新排列,编码可能会改变等等。如果你手动编辑你的XML,它可以是一个大问题。 – bortzmeyer

4

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

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

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); 
+7

它很简单,便宜! :P – Schwern

+0

不要讨厌playa ... :-) –

+5

至少Perl部分简单而简洁。 – mirod