Я должен разбирать XML, содержащий внешние ссылки, в которых есть атрибуты с разрывами строк. Используя SimpleXML, разрывы строк кажутся потерянными. В соответствии с другим вопросом stackoverflow , разрывы строк должны быть действительными (хотя и гораздо менее идеальными!) Для XML.
Почему они потеряны? [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! ) )
Объект для новой строки:
, Я играл с вашим кодом, пока не нашел что-то, что делало трюк. Это не очень элегантно, я предупреждаю вас:
//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-синтаксического анализатора, который newlines в значениях атрибута представляет собой простые пробелы. См. Нормализацию значения атрибута в спецификации 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);
«.» и "<as: eol />" были там, потому что мне нужно было добавить перерывы в этом случае. Новые строки «\ n» могут быть заменены на все, что вам нравится.
После замены просто загрузите xml-строку как объект SimpleXMLElement:
$xmlo = new SimpleXMLElement( $xml );
И вуаля
Ну, этот вопрос старый, но, как и я, кто-то может прийти на эту страницу в конце концов. У меня был несколько иной подход, и я думаю, что из них было изящнее.
Внутри 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, это может быть любой уникальный символ.