Как я могу найти и заменить текст в XML, используя Perl? - PullRequest
2 голосов
/ 12 января 2010

Мой 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» в значении поля prop, под всеми родительскими тегами, которые начинаются с RU в perl, на «b.com». Как получить изменения в виде XML-файла?

Ответы [ 3 ]

8 голосов
/ 13 января 2010

Предполагая, что ваш XML правильно сформирован (это не так), вы можете использовать несколько модулей CPAN для этой работы. Большинство из них будет включать в себя анализ документа, поиск вашего бита с помощью запроса 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>
4 голосов
/ 12 января 2010

Возьмите парсер XML с CPAN и используйте его. Они там по причине.

Как только вы это сделаете, это несколько довольно простых выражений XPath для получения нужных вам узлов, а затем некоторая быстрая замена текста на самих определенных атрибутах.

3 голосов
/ 13 января 2010

Использование следующей таблицы стилей

<?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);
...