【问题标题】:How to modify the content in the xml file except inside a particular tag如何修改 xml 文件中的内容,除了特定标签内
【发布时间】:2014-09-05 16:44:38
【问题描述】:

我尝试修改 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>

【问题讨论】:

  • 为什么不使用 xml 解析器结束 xml 生成器来转换 xml?

标签: regex perl


【解决方案1】:

使用适当的 XML 解析器。以下是我将如何处理 XML::XSH2,一个围绕 XML::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】:
     (\d{4}\.\d{2})(?!((?!<link>).)*<\/link>)
    

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

    查看演示

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

    【讨论】:

    • @Jens :我不知道如何使用 xml 生成器来做到这一点。你能这样告诉我吗?
    • 标签内的内容可以是任何内容,不需要只有副标题。例如: hello abc 1234.54 链 。我可以看到你的模式并没有给我所有的可能性。你能详细解释一下吗。 Avinash Raj 为我提供的所有情况都很好。
    • @Praveen 立即检查。也请参见演示。它给出了所有结果。
    • @Praveen 这不是正确的解决方案。如果数字和&lt;/link&gt; 标签之间有空格,它将不起作用。见regex101.com/r/pP3pN1/21
    • @AvinashRaj 直到现在才检查你的回答。newaz 是的,现在看起来很相似。让我尝试更多。
    【解决方案3】:

    正则表达式解决方案

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

    $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>
    

    【讨论】:

      【解决方案4】:

      下面的正则表达式将匹配所有采用这种格式\d4{}\.\d{2} 的数字,&lt;link&gt; 标记内的数字除外。

      正则表达式:

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

      替换字符串:

      <prv>$1</prv>
      

      DEMO

      【讨论】:

        猜你喜欢
        • 2014-08-03
        • 2015-09-17
        • 2022-01-20
        • 2015-02-20
        • 1970-01-01
        • 1970-01-01
        • 2018-07-05
        • 1970-01-01
        • 2016-11-26
        相关资源
        最近更新 更多