我必须解析外部提供的XML,该XML具有包含换行符的属性。使用SimpleXML,换行似乎丢失了。根据{{3}},换行符应该对XML有效(尽管远远不够理想!)。
为什么他们输了? [edit] 我该如何保存它们? [/ edit]
这是一个演示文件脚本(请注意,当换行符不在属性中时,它们会被保留)。
包含嵌入式XML的PHP文件
$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!
)
)
答案 0 :(得分:12)
使用SimpleXML,换行符似乎丢失了。
是的,这是预期的......事实上,任何符合要求的XML解析器都需要属性值中的换行符表示简单空格。请参阅XML规范中的attribute value normalisation。
如果属性值中应该有一个真正的换行符,那么XML应该包含
个字符引用而不是原始换行符。
答案 1 :(得分:4)
新行的实体为
。我玩了你的代码,直到找到了解决问题的方法。它不是很优雅,我警告你:
//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);
根据您的示例,假设是在节点或属性中出现的任何新行将在下一行中包含更多文本,而不是<
来打开新元素。
如果您的下一行包含一些包含在行级元素中的文本,那么这当然会失败。
答案 2 :(得分:1)
假设$ xmlData在发送到解析器之前是您的XML字符串,这应该用正确的实体替换属性中的所有换行符。我遇到了来自SQL Server的XML问题。
$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 <
使用正则表达式可能更简单,但对我来说这不是一个强点。
答案 3 :(得分:1)
以下是使用该特定XML片段中的相应字符引用替换新行的代码。在解析之前运行此代码。
$replaceFunction = function ($matches) {
return str_replace("\n", " ", $matches[0]);
};
$xml = preg_replace_callback(
"/<data Title='[^']+' Remarks='[^']+'/i",
$replaceFunction, $xml);
答案 4 :(得分:0)
这对我有用:
首先,将xml作为字符串:
$xml = file_get_contents($urlXml);
然后进行替换:
$xml = str_replace(".\xe2\x80\xa9<as:eol/>",".\n\n<as:eol/>",$xml);
“。”和“&lt; as:eol /&gt;”在那里是因为我需要在这种情况下添加休息时间。新行“\ n”可以替换为您喜欢的任何内容。
替换后,只需将xml-string加载为SimpleXMLElement对象:
$xmlo = new SimpleXMLElement( $xml );
EtVoilà
答案 5 :(得分:0)
嗯,这个问题很老但是和我一样,有人可能会最终来到这个页面。 我的方法略有不同,我认为这些都是最优雅的。
在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,它可以是任何唯一的字符。