2010-10-22 1 views
4

В течение жизни я не могу понять документацию XML :: Twig для обработки сущности.Как я могу добавить объявления сущностей через XML :: Twig программно?

У меня есть XML, который я генерирую с помощью HTML :: Tidy. Вызов заключается в следующем:

my $tidy = HTML::Tidy->new({ 
    'indent'   => 1, 
    'break-before-br' => 1, 
    'output-xhtml' => 0, 
    'output-xml'  => 1, 
    'char-encoding' => 'raw', 
}); 

$str = "foo   bar"; 
$xml = $tidy->clean("<xml>$str</xml>"); 

, который производит:

<html> 
    <head> 
    <meta content="tidyp for Linux (v1.02), see www.w3.org" name="generator" /> 
    <title></title> 
    </head> 
    <body>foo &nbsp; bar</body> 
</html> 

XML :: Twig (по понятным причинам) barfs на &nbsp;. Я хочу сделать некоторые преобразования, запустив его через XML :: Twig:

my $twig = XML::Twig->new(
    twig_handlers => {... handlers ...} 
); 

$twig->parse($xml); 

$twig->parse линия barfs на &nbsp;, но я не могу понять, как добавить элемент &nbsp;программно. Я пробовал такие вещи, как:

my $entity = XML::Twig::Entity->new("nbsp", "&#160;"); 
$twig->entity_list->add($entity); 
$twig->parse($xml); 

... но без радости.

Пожалуйста, помогите =)

ответ

3
use strict; 
use XML::Twig; 

my $doctype = '<?xml version="1.0" encoding="utf-8"?><!DOCTYPE html [<!ENTITY nbsp "&#160;">]>'; 
my $xml = '<html><head><meta content="tidyp for Linux (v1.02), see www.w3.org" name="generator" /><title></title></head><body>foo &nbsp; bar</body></html>'; 

my $xTwig = XML::Twig->new(); 

$xTwig->safe_parse($doctype . $xml) or die "Failure to parse XML : [email protected]"; 

print $xTwig->sprint(); 
+0

Это довольно близко к тому, что я (в идеале) хотел бы. Он по-прежнему полагается на манипуляции с текстом (в моем коде), а не на использование API XML :: Twig с литеральными данными, но я мог бы просто использовать это, чтобы объявить стандартное DTD для моих входящих данных. Упрощенный для утилиты, и это может быть принятый ответ (после того, как я возился с ним) –

+0

Я, наконец, принял это как лучший ответ. Я закончил делать что-то немного другое, но все-таки манипулирование текстами. Это, вероятно, лучшее общее решение. –

1

Там, может быть, лучший способ, но ниже код работает для меня:

my $filter = sub { 
    my $text = shift; 
    my $ascii = "\x{a0}"; # non breaking space 
    my $nbsp = '&nbsp;'; 
    $text =~ s/$ascii/$nbsp/; 
    return $text; 
}; 

XML::Twig->new(output_filter => $filter) 
     ->parse_html($xml) 
     ->print; 
+0

Я немного нерешительно, чтобы делать регулярное выражение регулярного выражения на XML, если есть программный подход. Я сохраню это в резерве, если я не смогу найти способ, который более «правильный» для его достижения (спасибо). –

5

Грязный, но эффективный, трюк в таком случае, как это было бы для добавления поддельной декларации DTD.

Тогда XML :: Parser, который выполняет синтаксический анализ, предположит, что сущность определена в DTD и не будет на ней зависеть.

Чтобы избавиться от поддельной декларации DTD, вы можете вывести корень ветки. Если вам нужно другое объявление, создайте его и замените текущий:

#!/usr/bin/perl 

use strict; 
use warnings; 

use XML::Twig; 

my $fake_dtd= '<!DOCTYPE head SYSTEM "foo"[]>'; # foo may not even exist 

my $xml='<html> 
    <head> 
    <meta content="tidyp for Linux (v1.02), see www.w3.org" name="generator" /> 
    <title></title> 
    </head> 
    <body>foo &nbsp; bar</body> 
</html>'; 

XML::Twig->new->parse($fake_dtd . $xml)->root->print; 
+0

Hmm .. спасибо. Это на самом деле очень полезно! –