Используйте perl LibXML Element-> getAttribute () без расширения юникодных сущностей в значении - PullRequest
0 голосов
/ 27 февраля 2019

В настоящее время я пытаюсь создать сценарий perl, который использует LibXML для обработки данных в шрифте SVG.

В шрифте SVG каждый символ определяется как элемент глифа с атрибутом Юникод, который определяет его юникодадрес в виде юникодного объекта;вот так:

<glyph unicode="&#x2000;" />

Часть желания, которую я хочу сделать, это взять значение атрибута unicode каждого элемента глифа и обработать его как строку.Однако когда я использую Element-> getAttribute ('unicode');против узла глифа он возвращает «широкий символ», который отображается в виде прямоугольника-заполнителя, что заставляет меня поверить, что он расширяет сущность юникода в символ юникода и возвращает его.

Когда я создаю свой синтаксический анализатор, я устанавливаю значение параметра расширения_ 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.

Ответы [ 2 ]

0 голосов
/ 28 февраля 2019

Метод serializeContent () может сделать то, что вам нужно:

my $xml = '<doc>
  <glyph unicode="&#x2000;" />
</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();

Какие выходные данные:

&#x2000;

Я подозреваю, что expand_entities опция не относится к числовым символам.Документация неясна, и я не смотрел на источник.

В более общем случае, когда вы делаете хотите, чтобы все сущности были расширены, и просто хотите, чтобы действительные символы, которые эти сущности представляли, выдаже не нужно звонить getAttribute().Каждый объект узла использует интерфейс связанный хеш , так что вы можете просто сделать это:

my $text = $glyph->{unicode};
0 голосов
/ 27 февраля 2019

Возможно, это не тот ответ, который вы ищете, но IMHO 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="&#x2000;" />

Тестовый прогон:

$ perl dummy.pl
<glyph unicode="&#x2000;"/>
' ' is 8192 (U+2000)

ОБНОВЛЕНИЕ: Документация для expand_entities ИМХО вводит в заблуждение.В нем говорится о «сущностях», но, очевидно, это означает ENTITY определений, то есть новых сущностей, введенных в документ.Документация libxml2 , к сожалению, не так понятна.Но это старое сообщение , кажется, указывает на ожидаемое вами поведение, т.е.синтаксический анализатор 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="&lt;&author;&gt;">&lt;&author;&gt;</tag>

Тестовый прогон:

$ perl dummy.pl 0
toString():  <tag test="&lt;&author;&gt;">&lt;&author;&gt;</tag>
textContent: <Fluffy Bunny>
attribute:   <Fluffy Bunny>

$ perl dummy.pl 1
toString():  <tag test="&lt;Fluffy Bunny&gt;">&lt;Fluffy Bunny&gt;</tag>
textContent: <Fluffy Bunny>
attribute:   <Fluffy Bunny>
...