【问题标题】:Perl LibXML raw data from textContent?来自 textContent 的 Perl LibXML 原始数据?
【发布时间】:2012-04-25 19:35:35
【问题描述】:

给定以下 XML:

<?xml version="1.0" encoding="utf-8" ?> 
<Request>
    <form_submit>
        <form_submit id = 1424>
            <form_id>1424</form_id>
            <field1 id=’5’> <![CDATA[ test   ]]>   </field1>
            <field2 id=’6’> <![CDATA[ test2   ]]>   </field2>
        </form_submit>
    </form_submit>
</Request>

我正在尝试获取 field1 和 field2 元素的原始值。我正在使用以下代码:

foreach my $node ( $xml_request->findnodes('Request/*/*/*[@id]') )
{
    my $form_field_value = $node->textContent;
    print "Value:\"$form_field_value\"\n";
}

但是输出是:

Value:" test   "
Value:" test2  "

如何使用所有特殊字符检索原始数据和原样的准确数据?所以输出是:

Value:" <![CDATA[ test   ]]>   "
Value:" <![CDATA[ test2   ]]>   "

谢谢。

【问题讨论】:

  • 如果文本的XML是&amp;lt;foo&amp;gt;怎么办?
  • 仅供参考,您的要求带有糟糕的设计。

标签: perl libxml2


【解决方案1】:

我不是 libxml 专家。 然而,这是我在玩过你的 xml 和 libxml 之后可以弄清楚的。 CDATA 是一个节点/部分,不是文本的一部分。 下面的代码深入一层并为 cdata 子节点执行 toString() 和其他节点的 textContent。

foreach my $node ( $xml_request->findnodes('Request/*/*/*[@id]') )
{
    my $text;
    if($node->childNodes) {
        foreach my $child ($node->childNodes()) {
            if ($child->nodeType == XML::LibXML::XML_CDATA_SECTION_NODE) {
                $text .= $child->toString;
            } else {
                $text .= $child->textContent;
            }
        }
    } else {
        $text = $node->textContent;
    }
    print qq{"$text"\n};
}

将打印

" <![CDATA[ test   ]]>   "
" <![CDATA[ test2   ]]>   "

【讨论】:

  • $child-&gt;nodeName eq "cdata" 对我不起作用。我需要$child-&gt;nodeName eq "#cdata-section"。我把你的代码换成了更可靠的代码。
【解决方案2】:

您的示例数据是无效的 XML,除非您将 1424’5’’6’ 替换为 "1424""5""6",否则不会解析。

您已要求提供文本内容,并且得到了准确的信息。要获得您需要的内容,您必须搜索&lt;fieldN&gt; 元素的子元素,并对它们使用toString 方法。

这段代码显示了这个想法。请注意,CDATA 之前和之后的空格(原本会显示为单独的文本节点)已使用对象构造函数上的keep_blanks =&gt; 0 选项消除。

use strict;
use warnings;

use XML::LibXML;

my $xml_request = XML::LibXML->load_xml(string => <<'END', keep_blanks => 0);
<?xml version="1.0" encoding="utf-8" ?> 
<Request>
  <form_submit>
    <form_submit id = "1424">
      <form_id>1424</form_id>
      <field1 id="5"> <![CDATA[ test   ]]>   </field1>
      <field2 id="6"> <![CDATA[ test2   ]]>   </field2>
    </form_submit>
  </form_submit>
</Request>
END

foreach my $node ( $xml_request->findnodes('//form_submit/*[@id]/text()') ) {
  my $form_field_value = $node->toString;
  print qq(Value: "$form_field_value"\n);
}

输出

Value: "<![CDATA[ test   ]]>"
Value: "<![CDATA[ test2   ]]>"

编辑

ikegami 评论说问题中请求的输出包括 CDATA 部分周围的空格。我不知道这是否真的是要求的一部分,但这个编辑提供了一种方法来做到这一点。

使用 XML::LibXML::Reader 会更清楚,因为它有一个 readInnerXml 方法(类似于 JavaScript 的 innerHTML ),它完全可以做必要的事情。相反,该程序必须序列化 &lt;fieldN&gt; 节点的所有子节点,并将它们与 join 连接。

这是一个新的foreach 循环。程序的其余部分保持不变,除了 $xml_request 的构造,它必须将 keep_blanks 选项设置为 1 或完全删除。

foreach my $node ( $xml_request->findnodes('//*[starts-with(name(),"field")][@id]') ) {
  my $form_field_value = join '', map $_->toString, $node->childNodes;
  print qq(Value: "$form_field_value"\n);
}

输出

Value: " <![CDATA[ test   ]]>   "
Value: " <![CDATA[ test2   ]]>   "

【讨论】:

  • 他也想要周围的空间。
  • @ikegami: 撇号 - "\x27" - 是允许的。问题中的字符是 Unicode U+2019 - RIGHT SINGLE QUOTATION MARK - 无效。请提出评论而不是编辑我的答案。
  • @Namuna:CDATA 部分周围的空白是否重要,或者这个解决方案是否令人满意?
猜你喜欢
  • 1970-01-01
  • 2012-01-18
  • 2012-11-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-04-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多