从 XML 字符串中删除处理指令(<?xml 标签和内容)
Remove Processing Instruction (<?xml tags and content) from XML String
我在字符串中有这个标签:
<?xml:namespace prefix = o /?>
如何使用 PHP 和正则表达式从字符串中删除该标签和类似标签?
我试过了:
$clean = preg_replace('/<\?xml[^>]+\/>/im', '', $dirty);
你们非常接近 - 请注意“?”在右尖括号之前的最后:
<?xml:namespace prefix = o /?>
要匹配它,您还需要这个:
<?php
$clean=preg_replace('/<\?xml[^>]+\/\?>/im', '', $dirty);
?>
你在该字符串中的内容是 Processing Instruction (PI, see XML 1.0).
如果要使用 PCRE UTF-8 修饰符从预期为 UTF-8 编码 w/o 的字符串中删除这些 PI,则可以使用以下模式:
~
<\?
(?: [A-Za-z_:] | [^\x00-\x7F] ) (?: [A-Za-z_:.-] | [^\x00-\x7F] )*
(?: \?> | \s (?: [^?]* \?+ ) (?: [^>?] [^?]* \?+ )* >)
~x
它是从 a REX expression for XML Processing Instructions 到 PHP.
中使用的 PCRE 表达式的翻译
代码示例:
$str = "some string <?xml:namespace prefix = o /?> that is";
$pattern = '~
<\?
(?: [A-Za-z_:] | [^\x00-\x7F] ) (?: [A-Za-z_:.-] | [^\x00-\x7F] )*
(?: \?> | \s (?: [^?]* \?+ ) (?: [^>?] [^?]* \?+ )* >)
~x';
echo preg_replace($pattern, '', $str);
输出:
some string that is
与之前给出的答案不同的是,这个正则表达式确实...
- ... 正确考虑结束顺序 ("
?>
")。特别是在处理指令中可以允许使用“>
”。
- ...没有要求限制处理指令的名称只能以“
xml
”开头。
- ...它实际上是在寻找一个名字作为开头序列的一部分。
- ...处理空和非空处理指令。
关于限制的一些值得一提的注意事项:
- 该模式用于浅层解析。也就是说,如果您还没有从可能包含文本的字符串中剥离其他标记构造,这些文本又可能看起来像这样的处理指令(例如 CDATA 块或注释),那么模式将错误匹配。
- 该模式匹配同样以“
<?xml
”开头的XML声明。这可以通过在开头“<?
”之后不查找 XML 保留名称来更改,并使用像“(?! [xX][mM][lL] (?: \?> | \s ) )
”这样的否定前瞻。
由于这些限制,也许值得考虑
正则表达式的替代方法
首先,直接用PHP的strip_tags
去掉处理指令会简单很多。它还会删除其他标签和评论。这可能并不总是需要的,它真的很简单:
strip_tags($str)
更加明确,因为正则表达式和 strip_tags
都使用 PHP 附带的 XML 解析器之一来剥离处理指令。例如 PHP 的 DOM 扩展名。它可以包装在一个函数中,以便轻松应用于字符串:
dom_strip_pis($str)
这样的示例函数也适用于您拥有的 XML 字符串,该字符串使用保留名称“xml
”作为前缀,这在 XML 中实际上并不正确。但是解析器不会阻塞它:
/**
* remove processing instructions from an XML string
*
* @author hakre <http://hakre.wordpress.com>
*
* @param string $xml
* @return string
*/
function dom_strip_pis($str) {
$doc = new DOMDocument;
$fragment = $doc->createDocumentFragment();
$saved = libxml_use_internal_errors(true);
$fragment-> appendXML($str);
libxml_use_internal_errors($saved);
foreach($fragment->childNodes as $node) {
if ($node instanceof DOMProcessingInstruction) {
$node->parentNode->removeChild($node);
}
}
return $doc->saveXML($fragment);
}
使用上一个示例中给出的 XML 解析器不会让您处理浅层解析。
我在字符串中有这个标签:
<?xml:namespace prefix = o /?>
如何使用 PHP 和正则表达式从字符串中删除该标签和类似标签?
我试过了:
$clean = preg_replace('/<\?xml[^>]+\/>/im', '', $dirty);
你们非常接近 - 请注意“?”在右尖括号之前的最后:
<?xml:namespace prefix = o /?>
要匹配它,您还需要这个:
<?php
$clean=preg_replace('/<\?xml[^>]+\/\?>/im', '', $dirty);
?>
你在该字符串中的内容是 Processing Instruction (PI, see XML 1.0).
如果要使用 PCRE UTF-8 修饰符从预期为 UTF-8 编码 w/o 的字符串中删除这些 PI,则可以使用以下模式:
~
<\?
(?: [A-Za-z_:] | [^\x00-\x7F] ) (?: [A-Za-z_:.-] | [^\x00-\x7F] )*
(?: \?> | \s (?: [^?]* \?+ ) (?: [^>?] [^?]* \?+ )* >)
~x
它是从 a REX expression for XML Processing Instructions 到 PHP.
中使用的 PCRE 表达式的翻译代码示例:
$str = "some string <?xml:namespace prefix = o /?> that is";
$pattern = '~
<\?
(?: [A-Za-z_:] | [^\x00-\x7F] ) (?: [A-Za-z_:.-] | [^\x00-\x7F] )*
(?: \?> | \s (?: [^?]* \?+ ) (?: [^>?] [^?]* \?+ )* >)
~x';
echo preg_replace($pattern, '', $str);
输出:
some string that is
与之前给出的答案不同的是,这个正则表达式确实...
- ... 正确考虑结束顺序 ("
?>
")。特别是在处理指令中可以允许使用“>
”。 - ...没有要求限制处理指令的名称只能以“
xml
”开头。 - ...它实际上是在寻找一个名字作为开头序列的一部分。
- ...处理空和非空处理指令。
关于限制的一些值得一提的注意事项:
- 该模式用于浅层解析。也就是说,如果您还没有从可能包含文本的字符串中剥离其他标记构造,这些文本又可能看起来像这样的处理指令(例如 CDATA 块或注释),那么模式将错误匹配。
- 该模式匹配同样以“
<?xml
”开头的XML声明。这可以通过在开头“<?
”之后不查找 XML 保留名称来更改,并使用像“(?! [xX][mM][lL] (?: \?> | \s ) )
”这样的否定前瞻。
由于这些限制,也许值得考虑
正则表达式的替代方法
首先,直接用PHP的strip_tags
去掉处理指令会简单很多。它还会删除其他标签和评论。这可能并不总是需要的,它真的很简单:
strip_tags($str)
更加明确,因为正则表达式和 strip_tags
都使用 PHP 附带的 XML 解析器之一来剥离处理指令。例如 PHP 的 DOM 扩展名。它可以包装在一个函数中,以便轻松应用于字符串:
dom_strip_pis($str)
这样的示例函数也适用于您拥有的 XML 字符串,该字符串使用保留名称“xml
”作为前缀,这在 XML 中实际上并不正确。但是解析器不会阻塞它:
/**
* remove processing instructions from an XML string
*
* @author hakre <http://hakre.wordpress.com>
*
* @param string $xml
* @return string
*/
function dom_strip_pis($str) {
$doc = new DOMDocument;
$fragment = $doc->createDocumentFragment();
$saved = libxml_use_internal_errors(true);
$fragment-> appendXML($str);
libxml_use_internal_errors($saved);
foreach($fragment->childNodes as $node) {
if ($node instanceof DOMProcessingInstruction) {
$node->parentNode->removeChild($node);
}
}
return $doc->saveXML($fragment);
}
使用上一个示例中给出的 XML 解析器不会让您处理浅层解析。