【问题标题】:Add new nodes/elements to XML::LibXML object向 XML::LibXML 对象添加新节点/元素
【发布时间】:2014-05-18 09:29:49
【问题描述】:

这是一个基本的 XML 文档示例

<book_reviewers>
    <results>
        <reviewer>
            <name>Anne</name>
            <profession>Catfish wrangler</profession>
        </reviewer>
        <reviewer>
            <name>Bob</name>
            <profession>Beer taster</profession>
        </reviewer>
        <reviewer>
            <name>Charlie</name>
            <profession>Gardener</profession>
        </reviewer>
    </results>
</book_reviewers>

我想补充一下:

<reviewer>
    <name>Joan</name>
    <profession>Jett</profession>
 </reviewer>

我已经尝试了许多解决方案的组合,这是一个至少不会引发错误的解决方案,但它也不起作用。

#!/usr/bin/perl
use XML::LibXML;
use strict;

my $filename = "cr.xml";

my $parser = XML::LibXML->new();
my $critic_details = $parser->parse_file("$filename") or die;
my $new_reviewer = $critic_details->documentElement;
my $reviewer_name = $critic_details->documentElement;
my $reviewer_prof = $critic_details->documentElement;
my $newnode = $critic_details->documentElement;

 for my $reviewers($critic_details->findnodes("book_reviewers/results/reviewers")){
     $new_reviewer = $reviewers->createElement("reviewer");
    $reviewer_name = $new_reviewer->addChild("name");
    $reviewer_name->appendText("Joan");
    $reviewer_prof = $new_reviewer->addChild("profession");
    $reviewer_prof->appendText("Jett");
    $newnode = $reviewers->addSibling($new_reviewer); #also tried addChild

}
print $critic_details->toString;

我得到的输出是:

<?xml version="1.0"?>
<book_reviewers>
        <results>
                <reviewer>
                        <name>Anne</name>
                        <profession>Catfish wrangler</profession>
                </reviewer>
                <reviewer>
                        <name>Bob</name>
                        <profession>Beer taster</profession>
                </reviewer>
                <reviewer>
                        <name>Charlie</name>
                        <profession>Gardener</profession>
                </reviewer>
        </results>
</book_reviewers>

这只是原始数据

非常感谢任何帮助 - 我对 Perl 和 XML 都很陌生 干杯

【问题讨论】:

    标签: xml perl xml-libxml


    【解决方案1】:

    有很多方法可以做到这一点

    这种方式分别创建节点并将其放在一起。它还没有准备好生产,因为它假设有一个部分

    #!/usr/bin/perl
    use XML::LibXML;
    use strict;
    
    my $filename = "cr.xml";
    
    my $parser = XML::LibXML->new();
    my $critic_details = $parser->parse_file("$filename") or die;
    
    my $reviewer  = $critic_details->findnodes("book_reviewers/results")->[0];
    
    my $node = XML::LibXML::Element->new("reviewer");
    
    my $p = XML::LibXML::Element->new("profession");
    my $pn = XML::LibXML::Text->new("Jett");
    $p->addChild($pn);
    
    my $n = XML::LibXML::Element->new("name");
    my $nn = XML::LibXML::Text->new("Joan");
    $n->addChild($nn);
    
    $node->addChild($p);
    $node->addChild($n);
    
    $reviewer->addChild($node);
    
    print $critic_details->toString;
    

    这给了这个

    <?xml version="1.0"?>
    <book_reviewers>
        <results>
            <reviewer>
                <name>Anne</name>
                <profession>Catfish wrangler</profession>
            </reviewer>
            <reviewer>
                <name>Bob</name>
                <profession>Beer taster</profession>
            </reviewer>
            <reviewer>
                <name>Charlie</name>
                <profession>Gardener</profession>
            </reviewer>
        <reviewer><profession>Jett</profession><name>Joan</name></reviewer></results>
    </book_reviewers>
    

    【讨论】:

    • 有没有办法让它缩进与现有数据一样?干杯
    • @KerynDrake,关于缩进,请看XML::LibXML::PrettyPrint
    【解决方案2】:

    只是为了帮助您解决XML::LibXML 的一些更简洁的事情并让您以更简单的方式了解 XML 的工作原理,我在这里发布了另一个答案。或许你也会从中找到一些有用的线索:

    use strict;
    use warnings;
    
    use utf8;
    
    use XML::LibXML;
    
    my $filename = "cr.xml";
    
    my $parser = XML::LibXML->new();
    my $critic_details = $parser->parse_file("$filename") or die;
    
    # find ALL the <book_reviewers><results> nodes
    my @results = $critic_details->findnodes("book_reviewers/results");
    die "no result node in xml-file" unless @results;
    
    my ($name, $profession) = ("Joan", "Jett");
    
    #
    # Here gets the work done, put this in a loop for more entries
    #
    
    # add a new <reviewer> node to the LAST <results>
    my $reviewer_node_child;
    my $reviewer_node = $results[-1]->addNewChild(undef, "reviewer");
    
    # create a child node
    $reviewer_node_child =  $reviewer_node->addNewChild(undef, "name");
    $reviewer_node_child->appendTextNode($name);
    
    # create a child node
    $reviewer_node_child =  $reviewer_node->addNewChild(undef, "profession");
    $reviewer_node_child->appendTextNode($profession);
    
    #
    # Done the heavy power lifting
    #
    
    use XML::LibXML::PrettyPrint;
    my $pretty = XML::LibXML::PrettyPrint->new(
      indent_string => ' ' x4,
      element       => {
        compact       => [qw| name profession | ],
        }
      );
    $pretty->pretty_print($critic_details);
    
    print $critic_details->toString;
    
    __END__
    

    这里需要addNewChild 方法中的undef。它们用于设置 XML-NameSpace,在这里您不需要,但在巨大的 XML 文档中确实是要走的路。

    另外,我添加了XML::LibXML::PrettyPrint 只是为了向您展示如何回到漂亮漂亮的语法。请原谅我在脚本末尾添加use…

    产生这个结果:

    <?xml version="1.0"?>
    <book_reviewers>
        <results>
            <reviewer>
                <name>Anne</name>
                <profession>Catfish wrangler</profession>
            </reviewer>
            <reviewer>
                <name>Bob</name>
                <profession>Beer taster</profession>
            </reviewer>
            <reviewer>
                <name>Charlie</name>
                <profession>Gardener</profession>
            </reviewer>
            <reviewer>
                <name>Joan</name>
                <profession>Jett</profession>
            </reviewer>
        </results>
    </book_reviewers>
    

    享受 XML 和 Perl,一个非常强大但令人生畏的工具组合!

    【讨论】:

    • 谢谢你——我真的很感激。是的,非常令人生畏,但我认为我正在到达那里,这要感谢像你这样的人,KeepCalmAndCarryOn 和 tobyink。有这么多的信息,但它往往没有太多意义,直到它被放在上下文中 - 再次感谢
    • 如果我有第二个具有相同结构但数据不同的文件,是否有一个函数可以全部抓取,即解析两个文件,然后添加第二个文件中的所有审阅者并将它们写入第一个还是你必须循环执行,手动抓取每个 - 我会在 CPAN 上查看,但该网站已经关闭了几个小时;干杯
    • 您可以拥有多个 XML::LibXML::Document 实例($critic_details 和 $additional_details)。然后,@additionals = $additional_details-&gt;findnodes("book_reviewers/results/reviewer") 将为您提供所有其他 &lt;reviewer&gt;-nodes 的数组。 --- 然后你可以遍历它们并制作我已经建议的循环。
    • 然而,如果你有完全相同的结构,你可以使用cloneNode 进行深度复制——保持additional_xml 不变:$results[-1]-&gt;addChild($_-&gt;cloneNode(1)) foreach ($additional_details-&gt;findnodes("book_reviewers/results/reviewer")) --- 有点紧凑的符号,但那是显示 TIMTOWDDI,尤其是在 foreach 循环中只有一个语句的情况下。
    • 再次感谢 VAnHoesel - 正如我们在澳大利亚所说的“你的血值得装瓶!!”
    【解决方案3】:

    可以使用XML::LibXML 将节点从一个XML 文档导入到另一个XML 文档中。这很有用,因为您不必使用对象显式构建新数据,而只需使用标准 XML 表示法即可。

    下面演示了这一点。通过在新文档中设置一个根节点,然后迭代找到的节点而不是只选择第一个节点,这可以很容易地扩展到多个重要的新审阅者。

    #!/usr/bin/perl
    
    use strict;
    use warnings;
    
    use XML::LibXML;
    
    my $dom = XML::LibXML->load_xml(IO => \*DATA);
    
    my $newnode = XML::LibXML->load_xml(string => <<'END_STRING')->findnodes('//*')->[0];
    <reviewer>
        <name>Joan</name>
        <profession>Jett</profession>
    </reviewer>
    END_STRING
    
    $dom->findnodes("book_reviewers/results")->[0]->addChild($newnode);
    
    print $dom->toString;
    
    __DATA__
    <book_reviewers>
        <results>
            <reviewer>
                <name>Anne</name>
                <profession>Catfish wrangler</profession>
            </reviewer>
            <reviewer>
                <name>Bob</name>
                <profession>Beer taster</profession>
            </reviewer>
            <reviewer>
                <name>Charlie</name>
                <profession>Gardener</profession>
            </reviewer>
        </results>
    </book_reviewers>
    

    输出:

    <?xml version="1.0"?>
    <book_reviewers>
        <results>
            <reviewer>
                <name>Anne</name>
                <profession>Catfish wrangler</profession>
            </reviewer>
            <reviewer>
                <name>Bob</name>
                <profession>Beer taster</profession>
            </reviewer>
            <reviewer>
                <name>Charlie</name>
                <profession>Gardener</profession>
            </reviewer>
        <reviewer>
        <name>Joan</name>
        <profession>Jett</profession>
    </reviewer></results>
    </book_reviewers>
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-08-05
      • 2018-05-31
      • 2018-05-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-06-18
      • 2013-06-21
      相关资源
      最近更新 更多