我目前正在尝试创建一个使用LibXML来处理SVG字体数据的perl脚本。
在SVG字体中,每个字符都被定义为带有unicode属性的字形元素,该属性以unicode实体的形式定义其unicode地址;像这样:
<glyph unicode=" " />
我想要做的一部分就是获取每个字形元素的unicode属性的值,并将其像字符串一样处理。但是,当我使用Element-> getAttribute('unicode');时,在字形节点上,它返回一个“宽字符”,显示为占位符矩形,这使我相信它将Unicode实体扩展为Unicode字符并返回该字符。
当我创建解析器时,我将expand_entities设置为0,所以我不确定还能做些什么来防止这种情况。我对XML处理非常陌生,所以我不确定我是否真正了解正在发生的事情,或者甚至认为这是可以预防的。
这是一个代码示例:
use utf8;
use open ':std', ':encoding(UTF-8)';
use strict;
use warnings;
use XML::LibXML;
$XML::LibXML::skipXMLDeclaration = 1;
my $xmlFile = $ARGV[0];
my $parser = XML::LibXML->new();
$parser->load_ext_dtd(0);
$parser->validation(0);
$parser->no_network(1);
$parser->recover(1);
$parser->expand_entities(0);
my $xmlDom = $parser->load_xml(location => $xmlFile);
my $xmlDomSvg = XML::LibXML::XPathContext->new();
$xmlDomSvg->registerNs('svg', 'http://www.w3.org/2000/svg');
foreach my $myGlyph ($xmlDomSvg->findnodes('/svg:svg/svg:defs/svg:font/svg:glyph', $xmlDom))
{
my $myGlyphCode = $myGlyph->getAttribute('unicode');
print $myGlyphCode . "\n";
}
注意:如果运行print $ myGlyph-> toString();,输出中的unicode实体不会扩展,因此为什么我得出结论说扩展发生在getAttribute方法中。
答案 0 :(得分:2)
这可能不是您要寻找的答案,但是恕我直言getAttribute
为您提供了足够的信息(例如,Perl字符串)以另一种方式解决您的问题。您正在尝试将该Perl字符串写入非UTF8文件,这就是为什么会收到“宽字符”警告的原因。
一个精简示例,说明如何获取您要寻找的U+xxxx
值:
use strict;
use warnings;
use open qw(:encoding(UTF-8) :std);
use XML::LibXML;
my $dom = XML::LibXML->load_xml(IO => \*DATA)
or die "XML\n";
my $root = $dom->documentElement();
print $root->toString(), "\n";
my $attr = $root->getAttribute('unicode');
printf("'%s' is %d (U+%04X)\n", $attr, ord($attr), ord($attr));
exit 0;
__DATA__
<glyph unicode=" " />
试运行:
$ perl dummy.pl
<glyph unicode=" "/>
' ' is 8192 (U+2000)
更新:expand_entities
的文档是恕我直言的误导。它讨论的是“实体”,但显然意味着ENTITY
定义,即文档中引入的 new 实体。不幸的是,libxml2 documentation并不清晰。但是这个old message似乎表明您描述的行为是预期的,即。 XML解析器应始终替换预定义的实体:
#!/usr/bin/perl
use warnings;
use strict;
use XML::LibXML;
my $parser = XML::LibXML->new({
expand_entities => $ARGV[0] ? 1 : 0,
});
my $dom = $parser->load_xml(IO => \*DATA)
or die "XML\n";
my $root = $dom->documentElement();
print "toString(): ", $root->toString(), "\n";
print "textContent: ", $root->textContent(), "\n";
my $attr = $root->getAttribute('test');
print "attribute: ${attr}\n";
exit 0;
__DATA__
<?xml version="1.0"?>
<!DOCTYPE foo [
<!ENTITY author "Fluffy Bunny">
]>
<tag test="<&author;>"><&author;></tag>
试运行:
$ perl dummy.pl 0
toString(): <tag test="<&author;>"><&author;></tag>
textContent: <Fluffy Bunny>
attribute: <Fluffy Bunny>
$ perl dummy.pl 1
toString(): <tag test="<Fluffy Bunny>"><Fluffy Bunny></tag>
textContent: <Fluffy Bunny>
attribute: <Fluffy Bunny>
答案 1 :(得分:1)
serializeContent()方法可能会满足您的要求:
my $xml = '<doc>
<glyph unicode=" " />
</doc>';
my $dom = XML::LibXML->load_xml(
string => $xml,
expand_entities => 0,
no_network => 1,
);
my($attr) = $dom->findnodes('//glyph[1]/@unicode');
say $attr->serializeContent();
哪个输出:
 
我怀疑expand_entities
选项不适用于数字字符实体。该文档尚不清楚,并且我没有查看源代码。
在更常见的情况下,您要做要扩展所有实体,而只希望这些实体表示的实际字符,则甚至不需要调用getAttribute()
。每个节点对象都使用tied hash接口,因此您可以执行以下操作:
my $text = $glyph->{unicode};