用PHP生成XML文档(转义字符)

时间:2010-10-18 07:53:28

标签: php xml

我正在从PHP脚本生成XML文档,我需要转义XML特殊字符。 我知道应该转义的字符列表;但是这样做的正确方法是什么?

是否应该使用反斜杠(\')或正确的方式转义字符? 是否有任何内置的PHP函数可以为我处理这个?

10 个答案:

答案 0 :(得分:36)

我创建了一个简单的函数,该函数使用XML中的five "predefined entities"进行转义:

function xml_entities($string) {
    return strtr(
        $string, 
        array(
            "<" => "&lt;",
            ">" => "&gt;",
            '"' => "&quot;",
            "'" => "&apos;",
            "&" => "&amp;",
        )
    );
}

用法示例Demo

$text = "Test &amp; <b> and encode </b> :)";
echo xml_entities($text);

输出:

Test &amp;amp; &lt;b&gt; and encode &lt;/b&gt; :)

使用str_replace可以达到类似的效果,但由于双重替换(未经测试,不推荐),它很脆弱:

function xml_entities($string) {
    return str_replace(
        array("&",     "<",    ">",    '"',      "'"),
        array("&amp;", "&lt;", "&gt;", "&quot;", "&apos;"), 
        $string
    );
}

答案 1 :(得分:34)

使用DOM类生成整个XML文档。它将处理我们甚至不想关心的编码和解码。


编辑:这是@Tchalvak批评的:

  

DOM对象创建一个完整的XML文档,它不容易仅仅为它自己编码一个字符串。

哪个错误,DOMDocument可以正确输出一个片段而不是整个文档:

$doc->saveXML($fragment);

给出:

Test &amp; <b> and encode </b> :)
Test &amp;amp; &lt;b&gt; and encode &lt;/b&gt; :)

如:

$doc = new DOMDocument();
$fragment = $doc->createDocumentFragment();

// adding XML verbatim:
$xml = "Test &amp; <b> and encode </b> :)\n";
$fragment->appendXML($xml);

// adding text:
$text = $xml;
$fragment->appendChild($doc->createTextNode($text));

// output the result
echo $doc->saveXML($fragment);

请参阅Demo

答案 2 :(得分:17)

htmlspecialchars()功能怎么样?

htmlspecialchars($input, ENT_QUOTES | ENT_XML1, $encoding);

注意:只有PHP 5.4.0或更高版本才能使用ENT_XML1标志。

带有这些参数的

htmlspecialchars()将替换以下字符:

  • &(&符号)变为&amp;
  • "(双引号)变为&quot;
  • '(单引号)变为&apos;
  • <(小于)变为&lt;
  • >(大于)变为&gt;

您可以使用get_html_translation_table()功能获取转换表。

答案 3 :(得分:13)

努力解决XML实体问题,以这种方式解决:

htmlspecialchars($value, ENT_QUOTES, 'UTF-8')

答案 4 :(得分:5)

为了获得有效的最终XML文本,您需要转义所有XML实体,并使用与XML文档处理相同的编码编写文本 - 指令说明它(<?xml中的“编码”线)。只要将重音字符编码为文档,就不需要对它们进行转义。

但是,在许多情况下,只使用htmlspecialchars转义输入可能会导致双重编码的实体(例如&eacute;会变成&amp;eacute;),所以我建议首先解码html实体:

function xml_escape($s)
{
    $s = html_entity_decode($s, ENT_QUOTES, 'UTF-8');
    $s = htmlspecialchars($s, ENT_QUOTES, 'UTF-8', false);
    return $s;
}

现在,您需要确保所有重音字符在XML文档编码中都有效。我强烈建议始终以UTF-8编码XML输出,因为并非所有XML解析器都遵循XML文档处理指令编码。如果您的输入可能来自其他字符集,请尝试使用utf8_encode()

有一个特例,你的输入可能来自以下编码之一:ISO-8859-1,ISO-8859-15,UTF-8,cp866,cp1251,cp1252和KOI8-R - PHP对待它们都是一样的,但它们之间存在一些细微的差别 - 其中一些甚至iconv()都无法处理。我只能通过补充utf8_encode()行为来解决这个编码问题:

function encode_utf8($s)
{
    $cp1252_map = array(
    "\xc2\x80" => "\xe2\x82\xac",
    "\xc2\x82" => "\xe2\x80\x9a",
    "\xc2\x83" => "\xc6\x92",
    "\xc2\x84" => "\xe2\x80\x9e",
    "\xc2\x85" => "\xe2\x80\xa6",
    "\xc2\x86" => "\xe2\x80\xa0",
    "\xc2\x87" => "\xe2\x80\xa1",
    "\xc2\x88" => "\xcb\x86",
    "\xc2\x89" => "\xe2\x80\xb0",
    "\xc2\x8a" => "\xc5\xa0",
    "\xc2\x8b" => "\xe2\x80\xb9",
    "\xc2\x8c" => "\xc5\x92",
    "\xc2\x8e" => "\xc5\xbd",
    "\xc2\x91" => "\xe2\x80\x98",
    "\xc2\x92" => "\xe2\x80\x99",
    "\xc2\x93" => "\xe2\x80\x9c",
    "\xc2\x94" => "\xe2\x80\x9d",
    "\xc2\x95" => "\xe2\x80\xa2",
    "\xc2\x96" => "\xe2\x80\x93",
    "\xc2\x97" => "\xe2\x80\x94",
    "\xc2\x98" => "\xcb\x9c",
    "\xc2\x99" => "\xe2\x84\xa2",
    "\xc2\x9a" => "\xc5\xa1",
    "\xc2\x9b" => "\xe2\x80\xba",
    "\xc2\x9c" => "\xc5\x93",
    "\xc2\x9e" => "\xc5\xbe",
    "\xc2\x9f" => "\xc5\xb8"
    );
    $s=strtr(utf8_encode($s), $cp1252_map);
    return $s;
}

答案 5 :(得分:2)

如果您需要正确的xml输出,可以使用simplexml:

http://www.php.net/manual/en/simplexmlelement.asxml.php

答案 6 :(得分:1)

正确转义是获取正确XML输出的方法,但您需要为属性元素处理以不同方式转义。 (这是托马斯的回答是不正确的。)

我写了/偷了一些Java code一段时间,区分属性和元素转义。原因是XML解析器特别在属性中考虑所有空格特殊。

把它移植到PHP上应该是微不足道的(你可以使用Tomas Jancik的方法进行上述适当的转义)。如果您使用UTF-8

,则无需担心转义扩展实体

如果您不想移植我的Java代码,您可以查看基于流的XMLWriter并使用libxml,这样它应该非常有效。

答案 7 :(得分:0)

您可以使用以下方法: http://php.net/manual/en/function.htmlentities.php

这样,所有实体(html / xml)都被转义,你可以把你的字符串放在XML标签中

答案 8 :(得分:-1)

根据sadeghj的解决方案,以下代码对我有用:

/**
 * @param $arr1 the single string that shall be masked
 * @return the resulting string with the masked characters
 */
function replace_char($arr1)
{
    if (strpos ($arr1,'&')!== FALSE) { //test if the character appears 
        $arr1=preg_replace('/&/','&amp;', $arr1); // do this first
    }

    // just encode the
    if (strpos ($arr1,'>')!== FALSE) {
        $arr1=preg_replace('/>/','&gt;', $arr1);
    }
    if (strpos ($arr1,'<')!== FALSE) {
        $arr1=preg_replace('/</','&lt;', $arr1);
    }

    if (strpos ($arr1,'"')!== FALSE) {
        $arr1=preg_replace('/"/','&quot;', $arr1);
    }

    if (strpos ($arr1,'\'')!== FALSE) {
        $arr1=preg_replace('/\'/','&apos;', $arr1);
    }

    return $arr1;
}

答案 9 :(得分:-2)

 function replace_char($arr1)
 {
  $arr[]=preg_replace('>','&gt', $arr1); 
  $arr[]=preg_replace('<','&lt', $arr1);
  $arr[]=preg_replace('"','&quot', $arr1);
  $arr[]=preg_replace('\'','&apos', $arr1);
  $arr[]=preg_replace('&','&amp', $arr1);

  return $arr;
  }