Попытка отредактировать PCDATA в документе XML - PullRequest
0 голосов
/ 27 марта 2012

Один из наших процессов включает копирование-вставку из электронной таблицы Excel в документ редактора кислорода.Он работает довольно хорошо, но не ловит специальные символы, поэтому я пишу скрипт для их поиска и изменения.Я начал с XML :: Parser в потоковом режиме, но я не уверен, что пойду туда, где мне нужно, с этим подходом.

С одной стороны, поскольку анализатор (правильно) не заботится о порядке атрибутов, атрибуты могут (и действительно) возвращаться в другом порядке, что раздражает некоторых людей.Кроме того, в настоящее время я не могу последовательно идентифицировать PCDATA.И, кажется, немного сложнее пересобрать теги элементов ... и я не очень хорошо справлюсь с EMPTY-элементами.Я что-то здесь упускаю, или мне следует взглянуть на что-то еще, например, XML :: Twig?

Заранее спасибо всем (всем), кто нашел время ответить!

use strict;
use warnings;
use IO::File;
use XML::Parser;

my $xml = <<EOD;
<?xml version="1.0"?>
<messages>
  <message>
    <from id="t_8ur9k0" type="king">Maximus</from>
    <to>knave</to>
    <subject>My boots</subject>
    <body>I <i>really</i> want my riding boots. Bring them to me, at once!</body>
  </message>
</messages>
EOD

my $parser = new XML::Parser(Style => 'Stream', ErrorContext => 2);
$parser->setHandlers(Start => \&handle_start, 
      End => \&handle_end, 
      Char => \&handle_char,
      Default => \&handle_default);

$parser->parse($xml);

sub handle_start {
  my ($self, $tag, %attrs) = @_;
  my $atts = '';
  if (%attrs) {
    while ( my ($key, $val) = each(%attrs) ) {
      $atts .= " " . $key . '="' . $val . '"';
    }
  }
  print "<" . $tag . $atts . ">";
}

sub handle_end {
  my ($self, $tag) = @_;
  print "</" . $tag . ">";
}

sub handle_char {
  my ($self,$raw) = @_;
  if ( !($raw =~ m/\s/) ) {
    $raw =~ s/.*/FOO/;
  }
  print $raw;
}

sub handle_default {
  my ($self,$str) = @_;
  print $str;
}

1 Ответ

0 голосов
/ 27 марта 2012

XML::Parser передает информацию об атрибуте обработчику обратного вызова Start в правильном порядке.Атрибуты появляются в вашей программе не по порядку, потому что вы помещаете их в хеш в строке

my ($self, $tag, %attrs) = @_;

, который теряет порядок.

XML::Parser редко используется сам по себе,Вы можете использовать XML::Twig, но я предпочитаю XML::LibXML.

Вы не говорите, какие преобразования вы хотите сделать с данными, но эта программа воспроизводит ввод отдельно от(произвольно выбранный) элемент <subject>, который он удаляет.Обратите внимание на простое использование нотации XPath для манипулирования документом и множественные атрибуты элемента <from>, которые хранятся в порядке.

use strict;
use warnings;

use XML::LibXML;

my $doc = XML::LibXML->load_xml(string => <<XML);
<?xml version="1.0"?>
<messages>
  <message>
    <from id="t_8ur9k0" type="king" b="b" c="c" d="d" e="e" f="f" g="g">Maximus </from>
    <to>knave</to>
    <subject>My boots</subject>
    <body>I <i>really</i> want my riding boots. Bring them to me, at once!</body>
  </message>
</messages>
XML

my @nodes = $doc->findnodes('/messages/message/subject');
$nodes[0]->unbindNode;
print $doc->toString;

output

<?xml version="1.0"?>
<messages>
  <message>
    <from id="t_8ur9k0" type="king" b="b" c="c" d="d" e="e" f="f" g="g">Maximus </from>
    <to>knave</to>

    <body>I <i>really</i> want my riding boots. Bring them to me, at once!</body>
  </message>
</messages>

ОБНОВЛЕНИЕ

Это демонстрация изменения всех текстовых узлов независимо от структуры документа

use strict;
use warnings;

use XML::LibXML;

my $doc = XML::LibXML->load_xml(string => <<XML);
<?xml version="1.0"?>
<messages>
  <message>
    <from id="t_8ur9k0" type="king" b="b" c="c" d="d" e="e" f="f" g="g">Maximus </from>
    <to>knave</to>
    <subject>My boots</subject>
    <body>I <i>really</i> want my riding boots. Bring them to me, at once!</body>
  </message>
</messages>
XML

my @nodes = $doc->findnodes('//text()');
$_->setData(lc $_->data) for @nodes;
print $doc->toString;

вывод

<?xml version="1.0"?>
<messages>
  <message>
    <from id="t_8ur9k0" type="king" b="b" c="c" d="d" e="e" f="f" g="g">maximus </from>
    <to>knave</to>
    <subject>my boots</subject>
    <body>i <i>really</i> want my riding boots. bring them to me, at once!</body>
  </message>
</messages>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...