Как вставить литерал '&' с помощью setAttribute () - PullRequest
0 голосов
/ 04 ноября 2018

Я использую XML :: LibXML (2.0018; perl 5.16.3) У меня есть хеш, содержащий серию атрибутов, которые затем применяются к документу XML с использованием setAttribute(). Этот материал предназначен для обновления файла tomcat server.xml, который необходимо изменить для работы с внешним интерфейсом apache httpd и который выполняется сценариями непрерывного развертывания.

Добавление основных атрибутов работает нормально:

use XML::LibXML qw ();

...

my %tmphash = ( port => "8581", address => "127.0.0.1", ... );

...

Тогда в некотором методе, который принимает ссылку на хеш:

foreach my $key (keys %$hashConnRef) {
  $connector->setAttribute("$key" => $hasConnRef->{$key});
}

Все хорошо, до сих пор, где мне нужно добавить атрибут, который нуждается в литерале & в выводе, чтобы tomcat правильно его подобрал.

Атрибут, который будет помещен в файл server.xml в файле, должен выглядеть следующим образом ( желаемый результат ):

relaxedQueryChars="[]|{}^\`"<>" 

Однако, вызов setAttribute() удобно преобразует «&» в «&», что приводит к ( токовому выходу ):

relaxedQueryChars="[]|{}^\`"<>"

Я пытался экранировать (и дважды экранировать) запись в хэше, например:

relaxedQueryChars => "[]|{}^\\\`\"\<\>"

К сожалению, в первом случае он просто ставит \&#x60, а во втором он добавляет \ перед &. Как определить строку в хэше, чтобы она обрабатывалась через setAttribute и правильно выдавала &#x5c?

По запросу, вот полный пример:

/ tmp / min.xml (по сути, все из разорванного tomcat conf / server.xml):

<?xml version="1.0" encoding="utf-8"?>
<Server port="8385" shutdown="SHUTDOWN">
  <Service name="Catalina">
  </Service>
</Server>

И минимальный пример программы:

#!/usr/bin/perl -w

use strict;
use warnings;

use XML::LibXML qw ( );

my %tmphash = (
  port => "8381",
  address => "127.0.0.1",
  relaxedQueryChars => "[]|{}^\&#x5c;\&#x60;\&quot;\&lt;\&gt;"
  );

sub edit_server_xml {
  my ($serverFile, $hashConnRef) = @_;

  my $parser = XML::LibXML->new();

  my $doc = $parser->parse_file($serverFile);

  for my $server ($doc->findnodes("/Server")) {
    # delete all of the defined connectors
      for my $service ($server->findnodes("Service")) {
        for my $connector ($service->findnodes("Connector")) {
          $service->removeChild($connector);
        }
      }

      my $connector = $doc->createElement("Connector");
      for my $service ($server->findnodes("Service")) {
        foreach my $key (keys %$hashConnRef) {
          $connector->setAttribute("$key" => $hashConnRef->{$key});
        }

        $service->appendChild($connector);
        $service->appendTextNode("\n");
      }

    $doc->toFile($serverFile);
  }
}

edit_server_xml("/tmp/min.xml", \%tmphash);

Результирующая строка, которая неверна:

<Connector address="127.0.0.1" relaxedQueryChars="[]|{}^&amp;#x5c;&amp;#x60;&amp;quot;&amp;lt;&amp;gt;" port="8381"/>

1 Ответ

0 голосов
/ 04 ноября 2018

Я думаю, что в основном единственное, что вам нужно, это relaxedQueryChars => "[]|{}^\\\"<>" - не надо предварительно кодировать вещи, libxml позаботится обо всей необходимой кодировке сущностей:

#!perl
use strict;
use warnings;
use XML::LibXML;

my $doc = XML::LibXML->load_xml(string=>'<f/>');
$doc->documentElement->setAttribute('foo' => '[]|{}<>\\&#');
print $doc->toString

__END__

<?xml version="1.0"?> <f foo="[]|{}&lt;&gt;\&amp;#"/>

Ваш страх, что обратная косая черта "ускользает от следующего символа" в XML, не поддерживается Википедия - символ амперсанда & - это символ, который используется для кодирования объектов всех проблемных символов.

...