8

我必须解析外部提供的 XML,其中包含带有换行符的属性。使用 SimpleXML,换行符似乎丢失了。根据另一个 stackoverflow question,换行符对于 XML 应该是有效的(即使远不理想!)。

他们为什么会迷路?[编辑]我怎样才能保存它们?[/编辑]

这是一个演示文件脚本(请注意,当换行符不在属性中时,它们会被保留)。

带有嵌入式 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!
        )

)
4

6 回答 6

13

使用 SimpleXML,换行符似乎丢失了。

是的,这是意料之中的……事实上,任何符合标准的 XML 解析器都要求属性值中的换行符表示简单的空格。请参阅XML 规范中的属性值规范化

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

于 2009-09-22T00:02:39.840 回答
4

新行的实体是&#10;。我一直在玩你的代码,直到找到可以解决问题的方法。这不是很优雅,我警告你:

//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","&#10;", $xml);

Finally, replace any new line entities between >< with a new line:
$xml = str_replace(">&#10;<",">\n<", $xml);

根据您的示例,假设是节点或属性内出现的任何新行都将在下一行包含更多文本,而不是<打开新元素。

如果您的下一行有一些包含在行级元素中的文本,这当然会失败。

于 2009-09-21T23:46:06.557 回答
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", "&#10;", $attr); //do the replacement
    $newParts[] = $attr.">".$other; // put parts back together
}
$xmlData = "<".implode("<", $newParts); // put parts back together prefixing with <

可能可以使用正则表达式更简单地完成,但这对我来说不是一个强项。

于 2011-02-23T14:03:01.347 回答
1

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

$replaceFunction = function ($matches) {
    return str_replace("\n", "&#10;", $matches[0]);
};
$xml = preg_replace_callback(
    "/<data Title='[^']+' Remarks='[^']+'/i",
    $replaceFunction, $xml);
于 2017-01-27T17:01:34.667 回答
0

这对我有用:

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

    $xml = file_get_contents($urlXml);

然后进行替换:

    $xml = str_replace(".\xe2\x80\xa9<as:eol/>",".\n\n<as:eol/>",$xml);

这 ”。” 并且 "< as:eol/ >" 在那里,因为在这种情况下我需要添加中断。新行“\n”可以替换为您喜欢的任何内容。

替换后,只需将 xml-string 作为 SimpleXMLElement 对象加载:

    $xmlo = new SimpleXMLElement( $xml );

等等瞧

于 2010-10-29T13:51:52.850 回答
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,它可以是任何唯一的字符。

于 2011-11-27T12:38:53.320 回答