使用 Perl LibXML 读取包含 html 标签的 textContent
Using Perl LibXML to read textContent that contains html tags
如果我有以下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' 文本值,并希望 return 包含所有 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
我只是用这个作为一个更复杂情况的例子,希望它有意义。
谢谢!
在您的来源 XML 中,您需要将标签编码为实体或将该内容包装在 CDATA 部分中。
这是一个相当笨拙的补丁解决方案,但它有效:
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));
在 XML 中嵌入 HTML 的一个问题是 HTML 不一定是 'well formed'。例如 <br>
标签和 <img>
标签后面通常不会跟匹配的结束标签,如果没有结束标签,它在 XML 文档中是无效的,除非你 XML-转义整个字符串HTML,例如:
<EngTranslation eng_indx="0" goesWith="-1" index="0">You have <b>%1$d</b> view(s)</EngTranslation>
或使用 CDATA 部分:
<EngTranslation eng_indx="0" goesWith="-1" index="0"><![CDATA[You have <b>%1$d</b> view(s)]]></EngTranslation>
但是,如果您将 HTML 限制为始终格式正确,则可以使用 toString()
方法实现您想要的。
如果您在 <EngTranslation>
元素节点上调用 toString()
,输出将包含 <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 编码,因此不必为每个打印调用编码。
如果我有以下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' 文本值,并希望 return 包含所有 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
我只是用这个作为一个更复杂情况的例子,希望它有意义。
谢谢!
在您的来源 XML 中,您需要将标签编码为实体或将该内容包装在 CDATA 部分中。
这是一个相当笨拙的补丁解决方案,但它有效:
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));
在 XML 中嵌入 HTML 的一个问题是 HTML 不一定是 'well formed'。例如 <br>
标签和 <img>
标签后面通常不会跟匹配的结束标签,如果没有结束标签,它在 XML 文档中是无效的,除非你 XML-转义整个字符串HTML,例如:
<EngTranslation eng_indx="0" goesWith="-1" index="0">You have <b>%1$d</b> view(s)</EngTranslation>
或使用 CDATA 部分:
<EngTranslation eng_indx="0" goesWith="-1" index="0"><![CDATA[You have <b>%1$d</b> view(s)]]></EngTranslation>
但是,如果您将 HTML 限制为始终格式正确,则可以使用 toString()
方法实现您想要的。
如果您在 <EngTranslation>
元素节点上调用 toString()
,输出将包含 <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 编码,因此不必为每个打印调用编码。