使用Perl LibXML读取包含html标签的textContent

时间:2015-01-29 21:24:25

标签: html xml perl libxml2

如果我有以下XML:

<File id="MyTestApp/app/src/main/res/values/strings.xml">
    <Identifier id="page_title" isArray="0" isPlural="0">
        <EngTranslation eng_indx="0" goesWith="-1" index="0">My First App</EngTranslation>
        <Description index="0">Home page title</Description>
        <LangTranslation index="0">My First App</LangTranslation>
    </Identifier>
    <Identifier id="count" isArray="0" isPlural="0">
        <EngTranslation eng_indx="0" goesWith="-1" index="0">You have <b>%1$d</b> view(s)</EngTranslation>
        <Description index="0">Number of page views</Description>
        <LangTranslation index="0">You have <b>%1$d</b> view(s)</LangTranslation>
    </Identifier>     
</File>

我正在尝试阅读'EngTranslation'文本值,并希望返回包含任何HTML标记的完整值。例如,我有以下内容:

my $parser = XML::LibXML->new;
my $dom = $parser->parse_file("test.xml") or die;

foreach my $file ($dom->findnodes('/File')) {
  print $file->getAttribute("id")."\n";
  foreach my $identifier ($file->findnodes('./Identifier')) {
      print $identifier->getAttribute("id")."\n";
      print encode('UTF-8',$identifier->findnodes('./EngTranslation')->get_node(1)->textContent."\n");
      print encode('UTF-8',$identifier->findnodes('./Description')->get_node(1)->textContent."\n");
      print encode('UTF-8',$identifier->findnodes('./LangTranslation')->get_node(1)->textContent."\n");
  }
}

我得到的输出是:

MyTestApp/app/src/main/res/values/strings.xml
page_title
My First App
Home page title
My First App
count
You have %1$d view(s)
Number of page views
You have %1$d views

我希望得到的是:

MyTestApp/app/src/main/res/values/strings.xml
page_title
My First App
Home page title
My First App
count
You have <b>%1$d</b> view(s)
Number of page views
You have <b>%1$d</b> views

我只是把它作为一个更复杂的情况的例子,希望它是有道理的。

谢谢!

3 个答案:

答案 0 :(得分:0)

在源XML中,您需要将标记编码为实体或将该内容包装在CDATA部分中。

答案 1 :(得分:0)

这是一个相当猴子修补的解决方案,但它有效:

sub XML::LibXML::Node::innerXML{
  my ($self) = shift;
  join '', $self->childNodes();
}

…
say $identifier->findnodes('./Description')->get_node(1)->innerXML;

哦,如果编码成为问题,请使用toString方法,它的第一个参数处理编码。 (我做了use open,但xml中没有超出范围的字符。

如果你不喜欢猴子补丁。你可以将sub改为普通的并提供参数,如下所示:

sub myInnerXML{
  my ($self) = shift;
  join '', map{$_->toString(1)} $self->childNodes();
}

…
say myInnerXML($identifier->findnodes('./Description')->get_node(1));

答案 2 :(得分:0)

在XML中嵌入HTML的一个问题是HTML不一定是“格式良好”的。例如,<br>标记和<img>标记后面通常没有匹配的结束标记,没有结束标记,它在XML文档中无效,除非您XML转义整个HTML字符串,例如:

<EngTranslation eng_indx="0" goesWith="-1" index="0">You have &lt;b&gt;%1$d&lt;/b&gt; view(s)</EngTranslation>

或使用CDATA部分:

<EngTranslation eng_indx="0" goesWith="-1" index="0"><![CDATA[You have <b>%1$d</b> view(s)]]></EngTranslation>

但是,如果您将HTML限制为始终格式良好,则可以使用toString()方法实现所需。

如果您在toString()元素节点上调用<EngTranslation>,则输出将包含<EngTranslation>...</EngTranslation>包装器标记。因此,您需要在每个子节点上调用toString()并将结果连接在一起:

binmode(STDOUT, ':utf8');

foreach my $file ($dom->findnodes('/File')) {
    print $file->getAttribute("id")."\n";
    foreach my $identifier ($file->findnodes('./Identifier')) {
        print $identifier->getAttribute("id")."\n";
        my $html = join '', map { $_->toString } 
            $identifier->findnodes('./EngTranslation')->get_node(1)->childNodes;
        print $html."\n";
        print $identifier->findnodes('./Description')->get_node(1)->textContent."\n";
        print $identifier->findnodes('./LangTranslation')->get_node(1)->textContent."\n";
    }
}

注意我冒昧地使用binmode在输出文件句柄上设置UTF8编码,因此没有必要为每个打印调用encode。