PHP SimpleXML не сохраняет разрывы строк в атрибутах XML
Я должен проанализировать внешний предоставленный XML, который имеет атрибуты с разрывами строк в них. При использовании SimpleXML разрывы строк теряются. Согласно еще один вопрос stackoverflow, разрывы строк должны быть действительными (хотя и далеко не идеальными!) для XML.
почему они проиграли? [edit] и как я могу их сохранить? [/edit]
вот сценарий демонстрационного файла (обратите внимание, что когда разрывы строк не находятся в атрибуте, они консервированный.)
PHP файл со встроенным XML
$xml = <<<XML
<?xml version="1.0" encoding="utf-8"?>
<Rows>
<data Title='Data Title' Remarks='First line of the row.
Followed by the second line.
Even a third!' />
<data Title='Full Title' Remarks='None really'>First line of the row.
Followed by the second line.
Even a third!</data>
</Rows>
XML;
$xml = new SimpleXMLElement( $xml );
print '<pre>'; print_r($xml); print '</pre>';
выход из print_r
SimpleXMLElement Object
(
[data] => Array
(
[0] => SimpleXMLElement Object
(
[@attributes] => Array
(
[Title] => Data Title
[Remarks] => First line of the row. Followed by the second line. Even a third!
)
)
[1] => First line of the row.
Followed by the second line.
Even a third!
)
)
6 ответов
сущность новой строки
. Я играл с вашим кодом, пока не нашел то, что сделал трюк. Это не очень элегантно, предупреждаю вас:
//First remove any indentations:
$xml = str_replace(" ","", $xml);
$xml = str_replace("\t","", $xml);
//Next replace unify all new-lines into unix LF:
$xml = str_replace("\r","\n", $xml);
$xml = str_replace("\n\n","\n", $xml);
//Next replace all new lines with the unicode:
$xml = str_replace("\n"," ", $xml);
Finally, replace any new line entities between >< with a new line:
$xml = str_replace("> <",">\n<", $xml);
предположение, основанное на вашем примере, заключается в том, что любые новые строки, которые происходят внутри узла или атрибута, будут иметь больше текста в следующей строке, а не <
открыть новый элемент.
Это, конечно, не удалось бы, если бы ваша следующая строка имела некоторый текст, который был завернут в элемент уровня строки.
используя SimpleXML, разрывы строк кажутся потерянными.
Да, это ожидалось... фактически от любого соответствующего синтаксического анализатора XML требуется, чтобы новые строки в значениях атрибутов представляли простые пространства. См.нормализация значения атрибута в спецификации XML.
Если в значении атрибута должен был быть реальный символ новой строки, XML должен был включать
ссылка на символ, а не сырые строки.
предполагая, что $xmlData является вашей XML-строкой до ее отправки синтаксическому анализатору, это должно заменить все новые строки в атрибутах правильной сущностью. У меня была проблема с XML, поступающим из SQL Server.
$parts = explode("<", $xmlData); //split over <
array_shift($parts); //remove the blank array element
$newParts = array(); //create array for storing new parts
foreach($parts as $p)
{
list($attr,$other) = explode(">", $p, 2); //get attribute data into $attr
$attr = str_replace("\r\n", " ", $attr); //do the replacement
$newParts[] = $attr.">".$other; // put parts back together
}
$xmlData = "<".implode("<", $newParts); // put parts back together prefixing with <
вероятно, можно сделать более просто с регулярным выражением, но это не сильная сторона для меня.
вот код для замены новых строк соответствующей ссылкой на символ в этом конкретном фрагменте XML. Запустите этот код перед синтаксическим анализом.
$replaceFunction = function ($matches) {
return str_replace("\n", " ", $matches[0]);
};
$xml = preg_replace_callback(
"/<data Title='[^']+' Remarks='[^']+'/i",
$replaceFunction, $xml);
вот что сработало для меня:
во-первых, получить xml в виде строки:
$xml = file_get_contents($urlXml);
тогда сделайте замену:
$xml = str_replace(".\xe2\x80\xa9<as:eol/>",".\n\n<as:eol/>",$xml);
В "."и" " были там, потому что мне нужно было добавить перерывы в этом случае. Новые строки "\n " можно заменить на все, что угодно.
после замены просто загрузите xml-строку как объект SimpleXMLElement:
$xmlo = new SimpleXMLElement( $xml );
Et Voilà
Ну, этот вопрос старый, но, как и я, кто-то может прийти на эту страницу в конце концов. У меня немного другой подход, и я думаю, что самый элегантный из упомянутых.
внутри xml вы помещаете уникальное слово, которое вы будете использовать для новой строки.
изменить xml на
<data Title='Data Title' Remarks='First line of the row. \n
Followed by the second line. \n
Even a third!' />
а затем, когда вы получаете путь к нужному узлу в SimpleXML в строке вывода, напишите что-то вроде этого:
$findme = '\n';
$pos = strpos($output, $findme);
if($pos!=0)
{
$output = str_replace("\n","<br/>",$output);
это не должно быть ' \n, это может быть любой уникальный чар.