0

这个问题似乎以前经常被问到,但我发现没有有效的数据解决方案,它很长并且包含特殊字符,如“<”或“{”或......等等。

我正在服务器上向 PHP 提交一些巨大的 XML 数据,如下所示:

<root><id>1</id><text>Here is a very long text with

line breaks, white-spaces and many very unsual charchaters, e.g. < % & }

the text can be more then 5000 characters long

</text></root>

在服务器端,我试图获取文本标签之间的“原始数据”。“文本标签”中的原始数据可以包括任何你可以想象的东西:空格、换行符、奇怪的字符。我提交的是源代码和文本,由 CKEditor 和代码语法高亮器格式化。

我通读了这篇文章,基本上每个人都说“使用 XML 解析器”,比如 domDocument 不要使用 RegEx。

首先,例如,我尝试了几个 RegEx 语句。这不是我尝试的唯一一个。当数据包含括号并且数据太长时,它会失败:

//#<text[^>]*>[\s\S]*?</text>#
$regex = "#<".$element_name."[^>]*>[\s\S]*?</".$element_name.">#";

$found = preg_match($regex, $xml, $matches);

if ($found != false) 
{
    $result = $matches[0];
    return $result;
}

其次,我尝试了这个,如果标签内的数据不太奇怪,它会起作用。我认为解析器不喜欢括号“<”并且认为 xml 无效。

 function getTextBetweenTags($tag, $html, $strict=0)
{
    /*** a new dom object ***/
    $dom = new domDocument;

    /*** load the html into the object ***/
    if($strict==0)
    {
        $dom->loadXML($html);
    }
    else
    {
        $dom->loadHTML($html);
    }

    /*** discard white space ***/
    $dom->preserveWhiteSpace = false;

    /*** the tag by its tag name ***/
    $content = $dom->getElementsByTagname($tag);

    /*** the array to return ***/
    //$out = array();
    foreach ($content as $item)
    {
        /*** add node value to the out array ***/
        //$out[] = $item->nodeValue;
        /*** return only the first found element value ***/
        return $item->nodeValue;
    }
    /*** return empty string if nothing found ***/
    return "";
}

所以我的问题是:

如果我确切知道,数据中只有一个开始和结束的“文本”标签,用 PHP 读取原始数据的最佳方法是什么?

如果有人给我一个有效的正则表达式或代码片段,那就太好了。

对不起我的中等英语。

===回复回复===回复回复===回复回复===

好的,BogdanM 和 Steven 的两个答案都有效,但我最喜欢的答案来自 BogdanM。

我做了什么。让这个工作:

  1. 我在客户端站点上创建了自己的 XML,现在我使用 CDATA 告诉解析器数据的开始和结束位置
  2. 在服务器端,我使用 SimpleXML 来解析数据。使用 CDATA 解析它没有更多问题。不管数据多么“奇怪”。
  3. 我消除了使用 HTTP-GET 发送大数据的常见“新手错误”。我现在只使用 HTTP-POST 没有限制

再次感谢您的帮助。

4

2 回答 2

2

您是否也在生成 XML?因为如果你是,你应该把你的文本数据放在 CDATA 之间。然后使用 simplexml 或您选择的某些解析器加载您的 xml 并获取文本标记内容。确保您没有 UTF-8 字符或一些 XML 中根本不允许的字符:http: //www.w3.org/TR/2000/REC-xml-20001006#NT-Char

否则你可以这样做:

preg_match('#<text>(.+?)</text>#is', $xml, $matches);
echo $matches[1]; // your data between <text> and </text>
于 2013-09-19T22:17:04.853 回答
2

首先,您的原始正则表达式模式没问题,应该可以正常工作:

#<".$item_name."[^>]*>([\s\S]*?)</".$item_name.">#

但是,您可以对其进行更改以使其更具可读性/功能性等...

可能性

正则表达式 1

#<text>(.*)</text>#is

只需捕获text标签之间的所有内容。使用修饰符i来允许TEXTtext标记并s匹配.新行。

正则表达式 2

#<text.*?>(.*)</text>#is

您的原始正则表达式意味着您希望在开始text标记中收到额外的字符。开始标签内的.*?允许这样做 -?使其停在第一个>

正则表达式 3

#<(text).*?>(.*)</\1>#is

由于开始和结束标记名称相同(即text),您可以在开始标记周围放置括号以使其成为捕获组,并在结束标记中简单地引用\1- 因为它是第一个捕获组。

这意味着犯拼写错误的机会减少了!

正则表达式 4

#<('.$item_name.').*?>(.*)</\1>#is

让它更有活力。您可以用变量替换单词text(根据您的原件)。将它与捕获组混合并像Regex 3中那样引用,您只需插入变量一次,从而获得更清晰、更易读的代码。

比较 v 原始

#<('.$item_name.').*?>(.*)</\1>#is
#<".$item_name."[^>]*>([\s\S]*?)</".$item_name.">#

工作示例

使用上面的正则表达式 4

$string = "
<root><id>1</id><text>Here is a very long text with

line breaks, white-spaces and many very unsual charchaters, e.g. < % & }

the text can be more then 5000 characters long 

</text></root>";

preg_match('#<('.$item_name.').*?>(.*)</\1>#is', $string, $matches);
var_dump($matches);

/**
Output:

array(3) {
  [0]=>
  string(167) "<text>Here is a very long text with

line breaks, white-spaces and many very unsual charchaters, e.g. < % & }

the text can be more then 5000 characters long 

</text>"
  [1]=>
  string(4) "text"
  [2]=>
  string(154) "Here is a very long text with

line breaks, white-spaces and many very unsual charchaters, e.g. < % & }

the text can be more then 5000 characters long 

"
}

*/

注意:如果您无法让上述工作示例...工作...那么您能否提供(通过编辑您的问题或链接)一个它不起作用的示例案例?

于 2013-09-19T22:45:13.100 回答