如何修改xml文件中的内容,但在特定标记内除外

时间:2014-09-03 08:49:43

标签: regex perl

我尝试修改XML文件中的内容。如果模式位于特定标记中,则不应转换。

将转换文件其余部分中该模式的所有其他事件

在这里,我打算转换\d{4}\.\d{2} to <prv>\d{4}\.\d{2}</prv>。但<link>标记内的模式也会被修改。

Input:

<abc>A change to a 1343.44 good of  <link>subheading 1222.34</link> from 
within that subheading or any 4545.56 other chapter.</abc>


Expected Output:

<abc>A change to a <prv>1343.44</prv> good of  <link>subheading 1222.34</link> from 
within that subheading or any <prv>4545.56</prv> other chapter.</abc>

4 个答案:

答案 0 :(得分:2)

 (\d{4}\.\d{2})(?!((?!<link>).)*<\/link>)

如果链接标记的内容具有统一性,这将起作用。

参见演示

http://regex101.com/r/pP3pN1/19

答案 1 :(得分:2)

使用正确的XML解析器。这是我如何继续XML::XSH2XML::LibXML的包装:

open file.xml ;
for my $text in //text() {
    if $text/parent::link next ;
    perl { $parts = [ split /(\d{4}\.\d{2})/, $text ] } ;
    $text := insert text { shift @$parts } replace $text ;
    while { @$parts } {
        my $n = { shift @$parts } ;
        my $t = { shift @$parts } ;
        $t := insert text $t after $text ;
        insert chunk concat('<prv>', $n, '</prv>') after $text ;
        $text = $t ;
    }
}
save :b ;

答案 2 :(得分:1)

以下正则表达式将匹配此格式\d4{}\.\d{2}中的所有数字,但<link>标记内的数字除外。

<强>正则表达式:

(\d{4}\.\d{2})(?!(?:(?!<\/link>|<link>).)*<\/link>)

替换字符串:

<prv>$1</prv>

DEMO

答案 3 :(得分:1)

正则表达式解决方案

以下正则表达式将解决大多数情况。但是,如果链接元素嵌入另一个链接元素中,它将不会涵盖:

$xml =~ s{
    \b(\d{4}\.\d{2})\b
    (?!
        (?: (?!<link>). )* 
        </link>
    )
}{<prv>$1</prv>}sgx;

XML :: LibXML解决方案

更好的解决方案是使用实际的XML Parser。以下内容使用XML::LibXML来解析数据并根据您的规范插入prv代码。

use strict;
use warnings;

use XML::LibXML;

my $xml = XML::LibXML->load_xml( IO => \*DATA );

for my $node ( $xml->findnodes('//*/text()') ) {
    next if $node->nodePath() =~ m{/link/};

    my $parent = $node->parentNode();

    # Split on marked values
    my @values = split /\b(\d{4}\.\d{2})\b/, $node->data;

    $node->setData( shift @values );

    while ( my ( $num, $text ) = splice @values, 0, 2 ) {
        my $prv = XML::LibXML::Element->new('prv');
        $prv->appendText($num);
        $parent->insertAfter( $prv, $node );

        $node = XML::LibXML::Text->new($text);
        $parent->insertAfter( $node, $prv );
    }
}

print $xml->toString(), "\n";

__DATA__
<root>
<abc>A change to a 1343.44 good of  <link>subheading 1222.34</link> from 
within that 1717.17 subheading or any 4545.56 other chapter.</abc>
</root>

输出:

<?xml version="1.0"?>
<root>
<abc>A change to a <prv>1343.44</prv> good of  <link>subheading 1222.34</link> from 
within that <prv>1717.17</prv> subheading or any <prv>4545.56</prv> other chapter.</abc>
</root>