【问题标题】:Navigating XML file using XML::Twig使用 XML::Twig 导航 XML 文件
【发布时间】:2019-08-03 20:16:59
【问题描述】:

我必须说我是 Perl 和 XML:Twig 的新手,但我学得很快。您能提供的任何帮助将不胜感激。

基本上,我无法导航到 XML 文件中的某些节点以便提取信息。

我正在使用 TwigHandler 让我访问 XML 中的某个节点,特别是“选择”节点。 TwigHandler 对我来说工作得很好,因为我能够在这个级别提取我需要的一些信息。但是,我需要检查“选择”下的其他节点,但我不知道如何找到它们。

我在下面复制了我的 XML 的 sn-p,以便您可以看到它的样子。在其中您可以看到选择节点。我可以使用我的 Twig 处理程序毫无问题地访问属性“id”和字段“Name”,但我需要遍历 Selection 节点下的所有这些“消息”节点,以便从中提取所有属性他们每个人。我试图让“get_xpath”工作但无济于事。

请记住,我的 XML 中的每个选择节点下都有消息节点。您在下面的示例中只看到 2 个选择节点,但实际上我可以有数百个“选择”节点,每个节点都有“消息”节点作为子节点。我需要从我正在使用的当前“选择”节点下的“消息”节点中提取信息,即,我不关心可能位于不同“选择”节点下的其他“消息”节点。

<Selection id="54008473">
  <Name>Master</Name>
  <Contents>
    <Message refid="125796458" suppress="true" status="Unchanged"/>
    <Message refid="123991123" suppress="true" status="Unchanged"/>
    <Message refid="128054778" custom="true" status="New">
      <Content language="en"><![CDATA[<p>ada</p>]]></Content>
    </Message>
  </Contents>
  <Messages/>
  <MessagePriority>
    <Zone name="Insured Letter Intro">
      <MessageInstance id="125796375" name="LD Letter Introduction" status="Active" delivery="Mandatory" priority="1" suppressed="false" selected="true"/>
    </Zone>
    <Zone name="Insured Letter Logo">
      <MessageInstance id="125794623" name="Insured Letter Logo" status="Active" delivery="Mandatory" priority="1" suppressed="false" selected="true"/>
     </Zone>
  </MessagePriority>
</Selection>
<Selection id="54008475" datavaluerefid="54008479">
  <Name>RMBC</Name>
  <Contents>
    <Message refid="125796458" sameasparent="true" parentrefid="54008473" status="Unchanged"/>
    <Message refid="123991123" sameasparent="true" parentrefid="54008473" status="Unchanged"/>
    <Message refid="128054778" custom="true" status="New">
      <Content language="en"><![CDATA[<p>ada</p>]]></Content>
    </Message>
  </Contents>
  <Messages/>
  <MessagePriority>
     ...
  </MessagePriority>
</Selection>

【问题讨论】:

  • 你的问题到底是什么?
  • 你试过children的方法吗?还是first_child 一个? xmltwig.org 上的本教程可能对您有用:xmltwig.org/xmltwig/tutorial/index.html
  • 仅供参考:您的 XML 看起来已损坏/不完整。我稍微修改了一下。
  • 嗨 Stefan,这看起来很有希望。很抱歉给你一个不完整的xml文件,我的错。我会尝试将它添加到我的脚本中,希望我能得到相同的结果。我可能还有一些问题,但让我先尝试将其纳入我的脚本中,我会尽快回复您。太感谢了!安杰洛
  • 嗨 Stefan,这个代码太棒了!!!它正是我需要的。非常感谢您花时间回答我的问题。我的脚本可能会变得有点复杂,所以我可能需要小组的更多帮助。如果我这样做,我会打开一个新线程。再次感谢!安杰洛我选择了你的回答作为我的回答。如果您需要我做其他事情,请告诉我。

标签: xml perl xml-twig


【解决方案1】:

Selection 的处理程序中使用findnodes() 和相对XPath 来查找Contents/Message 子节点:

#!/usr/bin/perl
use warnings;
use strict;

use XML::Twig;

my %selections;

my $twig = XML::Twig->new(
    twig_handlers => {
        Selection => sub {
            #$_->print();
            print "selection id: ", $_->att('id'), "\n";

            my @messages;
            foreach my $message ($_->findnodes('./Contents/Message')) {
                #$message->print();
                print "message refid: ", $message->att('refid'), "\n";

                # store "refid" attribute in messages list
                push(@messages, $message->att('refid'));
            }

            # store collected Message nodes under selection ID
            $selections{ $_->att('id') } = \@messages;
        },
    }
);

$twig->parse(\*DATA);

while (my($id, $messages) = each %selections) {
    print "Selection '${id}' messages: @{ $messages }\n";
}

exit 0;

__DATA__
<?xml version="1.0" encoding="UTF-8"?>
<Root>
  <Selection id="54008473">
    <Name>Master</Name>
    <Contents>
      <Message refid="125796458" suppress="true" status="Unchanged"/>
      <Message refid="123991123" suppress="true" status="Unchanged"/>
      <Message refid="128054778" custom="true" status="New">
        <Content language="en"><![CDATA[<p>ada</p>]]></Content>
      </Message>
    </Contents>
    <Messages/>
    <MessagePriority>
      <Zone name="Insured Letter Intro">
        <MessageInstance id="125796375" name="LD Letter Introduction" status="Active" delivery="Mandatory" priority="1" suppressed="false" selected="true"/>
      </Zone>
      <Zone name="Insured Letter Logo">
        <MessageInstance id="125794623" name="Insured Letter Logo" status="Active" delivery="Mandatory" priority="1" suppressed="false" selected="true"/>
      </Zone>
    </MessagePriority>
  </Selection>
  <Selection id="54008475" datavaluerefid="54008479">
    <Name>RMBC</Name>
    <Contents>
      <Message refid="125796458" sameasparent="true" parentrefid="54008473" status="Unchanged"/>
      <Message refid="123991123" sameasparent="true" parentrefid="54008473" status="Unchanged"/>
      <Message refid="128054778" custom="true" status="New">
        <Content language="en"><![CDATA[<p>ada</p>]]></Content>
      </Message>
    </Contents>
    <Messages/>
    <MessagePriority>
      ...
    </MessagePriority>
  </Selection>
</Root>

试运行:

$ perl dummy.pl
selection id: 54008473
message refid: 125796458
message refid: 123991123
message refid: 128054778
selection id: 54008475
message refid: 125796458
message refid: 123991123
message refid: 128054778
Selection '54008473' messages: 125796458 123991123 128054778
Selection '54008475' messages: 125796458 123991123 128054778

【讨论】:

  • 嗨,我还有一个问题。我不知道我应该打开一个新线程还是继续这个线程。请指教。我是堆栈溢出的新手。无论如何我都会发布我的问题:由于 Stefan 的代码,我现在可以访问“选择/内容/消息”节点下的信息,但我无法在消息/内容字段中提取 CDATA(向下一级)。例如,上述 XML 中的“ada]]>”。如果有人能告诉我如何使用 TWIG 来获取那条数据,那就太好了。我可以有多个内容节点,并且需要从每个节点获取 CDATA。 - 安杰洛
  • 我在回答您的第二个问题时给出了如何提取CDATA 内容的解决方案。
  • 谢谢!我回答。它几乎是完美的,我只有在研究了你的代码后才能修复它。问候,安杰洛
猜你喜欢
  • 2019-08-14
  • 1970-01-01
  • 2018-08-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多