使用perl和LibXML从XML中提取节点并解析结果

时间:2013-12-30 15:43:49

标签: xml perl xml-parsing libxml2

我有一个问题,我可以肯定会使用一些帮助。首先,要温柔。我是perl和LibXML的新手。

我一直在解析文档并将元素放入一个数组中,然后将其写入电子表格列。在测试期间,发现一些节点具有多个同名的子节点。我需要将每个子节点的文本组合成数组的一个元素。

xml的(非常简化的)格式是:

<Group>
<title>
<description>
<reference>
<fixtext>
<check>
    <check-content> "Some text I want to pull"

但偶尔会是这样的:

<Group>
<title>
<description>
<reference>
<fixtext>
<check>
    <check-content> "Some text I want to pull"
    <check-content> "Some more text I want to pull and join to the first"

我可以将所有内容提取到<check>以下,但无法从该变量中提取<check-content>

我一直在做的是:

my @Check_Content;
my $Check_Content;
my $parser = XML::LibXML->new() or die $!;
my $doc1 = $parser->parse_file($filename1);
my $xc1 = XML::LibXML::XPathContext->new($doc1->documentElement() );
$xc1->registerNs(x => 'http://checklists.nist.gov/xccdf/1.1');

for my $Check ( $xc1->findnodes('//x:Group/x:Rule/x:check') ) { 

    print "This is Check $Check\n";

    my $result_string;

     for my $Check_Content ( $Check->findvalue('check-content') ) { 

     print "This is Check Content $Check_Content\n";

     $result_string .= $Check_Content->to_literal;
     }

 push (@Check_Content, $result_string);
 }

第一个印刷声明证明正在拉出<check>以下的所有内容。但是,第二个print语句始终为空。就好像它不再是XML格式而且无法拉动节点。

我已经使用了我能想到的每个变量('check-content'),即

  • ('/check-content')
  • ('//check-content')
  • ('/x:check-content')
  • ('//check-content')
  • ('//x:check-content')

可能有一个我错过了,但我不这么认为。

非常感谢任何帮助。

1 个答案:

答案 0 :(得分:2)

开始时要注意几点,在发布未来问题时请记住:

  • 您没有提供易于使用的测试用例。特别是:
    • 您的XML文档不完整且格式正确。
    • 您提供的XPath查询甚至与您提供的XML片段不匹配。
    • 您在XML中没有使用命名空间标记。
  • 您没有阅读perl为您提供的错误消息。

因此,这是一个适用于您的用例的有效XML文档:

<x:Group xmlns:x="http://checklists.nist.gov/xccdf/1.1">
  <x:title>
    <x:description>
      <x:reference>
        <x:fixtext>
          <x:check>
            <x:check-content> "Some text I want to pull"</x:check-content>
            <x:check-content> "Some more text I want to pull and join to the first"</x:check-content>
          </x:check>
        </x:fixtext>
      </x:reference>
    </x:description>
  </x:title>
</x:Group>

这里有一个(几乎完整的,除了顶部的初始解析代码)脚本来处理你的XML:

my @Check_Content;
my $Check_Content;
my $xc1 = XML::LibXML::XPathContext->new($doc1->documentElement() );
$xc1->registerNs(x => 'http://checklists.nist.gov/xccdf/1.1');

for my $Check ( $xc1->findnodes('//x:Group//x:check') ) {
  print "This is Check $Check\n";
  my $result_string;
  for my $Check_Content ( $Check->findvalue('x:check-content') ) {
    print "This is Check Content $Check_Content\n";
    $result_string .= $Check_Content->to_literal;
  }

  push (@Check_Content, $result_string);
}

当我在这个XML上运行这个脚本时,我得到了这个输出:

This is Check <x:check>
                <x:check-content> "Some text I want to pull"</x:check-content>
                <x:check-content> "Some more text I want to pull and join to the first"</x:check-content>
              </x:check>
This is Check Content  "Some text I want to pull" "Some more text I want to pull and join to the first"
Can't locate object method "to_literal" via package " "Some text I want to pull" "Some more text I want to pull and join to the first"" (perhaps you forgot to load " "Some text I want to pull" "Some more text I want to pull and join to the first""?) at ./hm.pl line 27, <DATA> line 15.

因此立即出现两个问题:

  • 两个节点都被提取为单个结果
  • findcontent()返回一个字符串;你不能打电话给to_literal()

所以解决这个问题:

  • 将您的findcontent()来电更改为findnodes()来电。
  • 鲍勃是你的叔叔。
祝你好运!