【问题标题】:Doing XPath using Perl使用 Perl 执行 XPath
【发布时间】:2012-08-17 01:35:17
【问题描述】:

我在 Window 7 机器上使用 Perl 进行编码。我可以使用下面的 XPath 代码从 XML 中提取数据

use strict;
use warning;

use XML::LibXML;

my $parser = XML::LibXML->new();
        my $doc    = $parser->parse_file($newfile);
        my $query  = "/tradenet/message/header/unique_ref_no/date/text( )";
        my($node)   = $doc->findnodes($query);
        $node->setData("$file_seq_number");  

但是,当我在不同的 XML 上使用相同的代码时,第二个文档的 xpath 如下所示:

/TradenetResponse/OutboundMessage/out:OutwardPermit/out:Declaration/out:Header/cac:UniqueReferenceNumber/cbc:SequenceNumeric

加上 Perl 代码,提取代码如下所示:

my $parser = XML::LibXML->new();
    my $doc    = $parser->parse_file($newfile);
    my $query  = "/TradenetResponse/OutboundMessage/out:OutwardPermit/out:Declaration/out:Header/cac:UniqueReferenceNumber/cbc:SequenceNumeric/text( )";
    my($node)   = $doc->findnodes($query);
    $node->setData("$file_seq_number");

使用第二个代码,我无法从第二个 XML 检索数据。我收到此错误“无法在 Perl.pl 第 5 行的未定义值上调用方法“setData”。

第二个 XPATH 地址中的“:”字符会影响代码吗?

【问题讨论】:

  • 使用严格;使用警告;应该在脚本的顶部。
  • 嗨,是的,我确实使用了严格和警告,它实际上位于代码块的顶部,但是,在这里发布整个内容会很长。感谢您的建议并非常感谢。
  • 但是,根据建议,我已将其添加到上面的代码中...谢谢!
  • 我想,您还必须为“未命名”元素提供命名空间。查看this discussion 了解更多详细信息 - 并寻找其他人,这实际上是一种非常流行的问题。 )

标签: perl xpath


【解决方案1】:

您必须定义 outcaccbc 的含义,以便 XPath 查询找到合适的节点:

my $doc = $parser->parse_file($newfile);
my $xpath_context = XML::LibXML::XPathContext->new($doc->documentElement());

# These URIs need to be the same as the ones in the source document
$xpath_context->registerNs('out', 'http://example.com/out.xsd');
$xpath_context->registerNs('cac', 'http://example.com/cac.xsd');
$xpath_context->registerNs('cbc', 'http://example.com/cbc.xsd');

my $query  = "/TradenetResponse/OutboundMessage/out:OutwardPermit/out:Declaration/out:Header/cac:UniqueReferenceNumber/cbc:SequenceNumeric/text( )";
my ($node) = $xpath_context->findnodes($query);

正如所承诺的,这是一个工作示例。一、测试输入文件:

<?xml version="1.0"?>

<!-- input.xml -->

<TradenetResponse xmlns:a="http://example.com/out.xsd"
                  xmlns:b="http://example.com/cac.xsd"
                  xmlns:c="http://example.com/cbc.xsd">
  <OutboundMessage>
    <a:OutwardPermit>
      <a:Declaration>
        <a:Header>
          <b:UniqueReferenceNumber>
            <c:SequenceNumeric>1234</c:SequenceNumeric>
          </b:UniqueReferenceNumber>
        </a:Header>
      </a:Declaration>
    </a:OutwardPermit>
  </OutboundMessage>
</TradenetResponse>

这是有效的 Perl 脚本:

#!/usr/bin/perl

# parse.pl

use strict;
use warnings;
use XML::LibXML;

my $parser = XML::LibXML->new();

my $newfile = "input.xml";
my $doc = $parser->parse_file($newfile);
my $xpath_context = XML::LibXML::XPathContext->new($doc->documentElement());

# These URIs need to be the same as the ones in the source document
$xpath_context->registerNs('out', 'http://example.com/out.xsd');
$xpath_context->registerNs('cac', 'http://example.com/cac.xsd');
$xpath_context->registerNs('cbc', 'http://example.com/cbc.xsd');

# Query wrapped for clarity                                                                                                         
my $query = "/TradenetResponse/OutboundMessage/out:OutwardPermit" .
            "/out:Declaration/out:Header/cac:UniqueReferenceNumber" .
            "/cbc:SequenceNumeric/text()";

my ($node) = $xpath_context->findnodes($query);

print "Value: " . $node->getData() . "\n";

我的输出是:

sean@localhost:~xmltest$ ./parse.pl 价值:1234

【讨论】:

  • 你好,肖恩,我尝试了上面的代码,用本地驱动器上的实际 XSD 更改了假路径,但仍然得到相同的错误。会继续努力..感谢您的建议...
  • 您将此标记为答案。你能做到吗?如果没有,我可以尝试为您提供一个工作示例。
  • 嗨,肖恩,我无意中标记了它。我很抱歉。如果您能提供一个工作样本,我将不胜感激。几乎两天都在破坏我的头......我现在将取消选中它。谢谢!
  • 肖恩...现在试试...非常感谢...真的很感激。
猜你喜欢
  • 2013-07-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-11-21
  • 2017-10-14
  • 2012-10-20
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多