Именованные объекты в инкапсулированном XML вызывают ошибки синтаксического анализа
У меня есть документы XML, которые содержат другие документы XML, инкапсулированные как CDATA, например:
<mds>
<md>
<value>
<![CDATA[<?xml version="1.0" encoding="UTF-8"?><record xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:dcterms="http://purl.org/dc/terms/">
<dc:title>some text containing &</dc:title></record>]]>
</value>
</md>
</mds>
Я извлекаю этот XML и заголовок dc: из него, используя LibXML:
$dcrawData = <get the CDATA from above>;
$dcDOM = $::PRSR->load_xml(expand_entities => 0, string => $dcRawData);
$dcTitle = $dcDOM->findvalue("//dc:title");
Затем я вставляю его в другой раздел XML, выполняя замену строки:
<mods:titleInfo>
<mods:title>some text containing &</mods:title>
</mods:titleInfo>
Как видите, сущность & раскрывается и становится одиночной &. Что является проблемой, потому что теперь результирующий XML генерирует ошибку разбора, потому что любой синтаксический анализатор ожидает здесь именованную сущность.
Есть ли способ предотвратить расширение LibXML именованных сущностей при использовании findvalue или перекодировать их перед использованием значения? Там могут быть другие в других записях. Опция expand_entities не имеет значения.
3 ответа
Хорошо, я думаю, что нашел решение. XML::Entities
выполнит работу по перекодированию сущностей в строке.
Однако мне нужно ограничить число символов, которые закодированы, только несколькими, иначе закодированная строка будет иметь объекты, которые не распознает анализатор xml.
Так что на данный момент я использую
$dcTitle = encode_entities($dcDOM->findvalue("//dc:title"),'&<>"');
кодировать только амперсанд и несколько специальных символов xml.
Затем я вставляю его в другой раздел XML, выполняя замену строки
Не. Если вы хотите вставить данные в XML-документ, вы должны сделать это с помощью API-интерфейса, поддерживающего XML, который будет обрабатывать любые необходимые экранирования для вас.
Затем я вставляю его в другой раздел XML, выполняя замену строки
Это та часть, которую вы делаете неправильно. Вы вставляете текст в XML, не превращая его в XML. (Это называется ошибкой впрыска.) Вам нужно убежать &
, <
и любые символы вне набора символов документа.
sub text_to_xml {
my ($s) = @_;
for ($s) {
s/&/&/g;
s/</</g;
s/"/"/g; # So it can be used for attributes too
s/'/'/g; # So it can be used for attributes too
}
return $s;
}
Не забывайте, что вам также необходимо кодировать его в соответствии с кодировкой документа.