PHP SimpleXML没有';t在XML属性中保留换行符

PHP SimpleXML没有';t在XML属性中保留换行符,php,xml,simplexml,Php,Xml,Simplexml,我必须解析外部提供的XML,这些XML的属性中有换行符。使用SimpleXML,换行符似乎丢失了。根据,对于XML,换行符应该是有效的(尽管远远不够理想!) 他们为什么迷路了?[编辑]如何保存它们?[/edit] 这是一个演示文件脚本(请注意,当换行符不在属性中时,它们将被保留) 带有嵌入式XML的PHP文件 $xml = <<<XML <?xml version="1.0" encoding="utf-8"?> <Rows> <data

我必须解析外部提供的XML,这些XML的属性中有换行符。使用SimpleXML,换行符似乎丢失了。根据,对于XML,换行符应该是有效的(尽管远远不够理想!)

他们为什么迷路了?[编辑]如何保存它们?[/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>';

新行的实体是

。我一直在玩你的代码,直到我发现了一些能起作用的东西。这不是很优雅,我警告你:

    $xml = file_get_contents($urlXml);
//首先删除任何缩进:
$xml=str_replace(“,”,$xml);
$xml=str_replace(“\t”,”,$xml);
//下一步替换将所有新行统一到unix LF中:
$xml=str_replace(“\r”、“\n”、$xml);
$xml=str\u replace(“\n\n”、“\n”、$xml);
//接下来,用unicode替换所有新行:
$xml=str_replace(“\n”、“10;”,$xml);
最后,用新行替换><之间的任何新行实体:
$xml=str_replace(“>
;\n
使用SimpleXML,换行符似乎丢失了

是的,这是意料之中的……事实上,任何一致的XML解析器都要求属性值中的换行符表示简单的空格


如果属性值中应该有一个真正的换行符,那么XML应该包含一个
字符引用,而不是一个原始换行符。

这就是我的工作原理:

首先,将xml作为字符串获取:

    $xml = str_replace(".\xe2\x80\xa9<as:eol/>",".\n\n<as:eol/>",$xml);
然后进行更换:

    $xmlo = new SimpleXMLElement( $xml );

Et Voilá

假设$xmlData在发送到解析器之前是您的XML字符串,这应该用正确的实体替换属性中的所有换行符。我遇到了来自SQL Server的XML的问题

<data Title='Data Title' Remarks='First line of the row. \n
Followed by the second line. \n
Even a third!' />
$parts=explode(“,$p,2);//将属性数据获取到$attr中
$attr=str_replace(“\r\n”,“
;”,$attr);//执行替换
$newParts[]=$attr.>“$other;//将部件重新组合在一起
}

$xmlData=“好吧,这个问题很老了,但像我一样,最终可能会有人来到这个页面。 我有一个稍微不同的方法,我认为这其中最优雅的是提到的

在xml中,您将使用一些独特的词来表示新行

将xml更改为

$findme  = '\n';
$pos = strpos($output, $findme);
if($pos!=0)
{
$output = str_replace("\n","<br/>",$output);

然后,当您在字符串输出中获得SimpleXML中所需节点的路径时,编写如下内容:

$replaceFunction = function ($matches) {
    return str_replace("\n", "&#10;", $matches[0]);
};
$xml = preg_replace_callback(
    "/<data Title='[^']+' Remarks='[^']+'/i",
    $replaceFunction, $xml);
$findme='\n';
$pos=strpos($output,$findme);
如果($pos!=0)
{
$output=str_replace(“\n”,“
,$output”);

它不必是“\n,它可以是任何唯一的字符。

以下是用该特定XML片段中的适当字符引用替换新行的代码。请在解析之前运行此代码

$replaceFunction=函数($matches){
返回str_replace(“\n”、“
;”、$matches[0]);
};
$xml=preg\u replace\u回调(

“/你应该在PHP主页中问这个问题。我想这是因为它是一个简单的xml解析器。你能再解释一下PHP主页的含义吗?最初你的问题是“为什么SimpleXML会这样做?”这是你可以问的问题,开发者而不是用户。明白了-谢谢你的推荐,Zilupe。现在bobince已经回答了”为什么SimpleXML会这么做?“我想我会把它保留在stackoverflow上,这样希望有人可以添加我必须保留换行符的其他选项!稍微澄清一下:换行符是有效的,但是XML解析器(为了符合规范)必须将它们减少到一个空格字符(见bobince链接第3项)。感谢链接bobince和TML的澄清。因此,我想我现在的问题是,如何保留这些换行符?我从SharePoint web服务接收到这些数据,因此我无法将XML更改为包含 。在这方面,有没有方法覆盖解析器遵从性?不幸的是,没有,XML在此po上非常不灵活int;如果web服务正在生成
\n
而它的意思是
,那么这就是一个bug。(这是一个令人惊讶的错误,因为这是任何XML序列化程序都应该正确使用的一个基本特性……当然,除非该服务使用正则表达式或字符串模板,而不是使用适当的XML库!)除非您有权访问子类或monkey patch您的XML解析器,否则您将无法更改它……我认为SimpleXML使用libxml,您不希望从PHP中处理它。预处理一般XML输入以放入
也有点不容易,因为您必须编写大部分XML解析器已经能够区分属性值中的换行符和直接在标记中的换行符之间的差异(如果
将是非法的)。像Anthony这样的黑客可以作为临时解决方案,如果精确的格式在此时被锁定。(对于那里的
代码
很抱歉,似乎在SO的
&;
标记中有一个缺陷,或者其他什么东西……)非常聪明!!!唯一的问题是我正在处理SharePoint web services中喷涌而出的大量SOAP封装的XML,所以做一些如此残忍的事情让我有点紧张。不过根据bobince的帖子,看起来我可能不得不朝这个方向走。我想知道是否有更优雅的方法来实现它。确切地说,问题是从技术上讲,新行在XML属性中是无效的。然而,解析器往往会修复很多问题。在所有情况下,无效实体都应该进行编码。最好的解决方案是修复源代码,但如果不可用,这似乎是合法的。
<data Title='Data Title' Remarks='First line of the row. \n
Followed by the second line. \n
Even a third!' />
$findme  = '\n';
$pos = strpos($output, $findme);
if($pos!=0)
{
$output = str_replace("\n","<br/>",$output);
$replaceFunction = function ($matches) {
    return str_replace("\n", "&#10;", $matches[0]);
};
$xml = preg_replace_callback(
    "/<data Title='[^']+' Remarks='[^']+'/i",
    $replaceFunction, $xml);