从XML String - >中删除处理指令(<! - ?xml标记和内容)

时间:2015-04-02 17:11:15

标签: php regex xml string processing-instruction

我在字符串中有这个标签:

<?xml:namespace prefix = o /?>

如何使用PHP和regex从字符串中删除那些和类似的标签?

我试过了:

$clean = preg_replace('/<\?xml[^>]+\/>/im', '', $dirty);

2 个答案:

答案 0 :(得分:1)

该字符串中的内容为Processing Instruction (PI, see XML 1.0)

如果要从未使用PCRE UTF-8修饰符进行UTF-8编码的字符串中删除这些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

与之前给出的答案不同的是,这个正则表达式确实......

  • ...正确考虑结束顺序(&#34; ?>&#34;)。特别是&#34; >&#34;可以在处理指令中使用。
  • ...没有要求将处理指令的名称限制为以&#34; xml&#34;开头。仅
  • ...它实际上是在寻找一个名称作为开场序列的一部分。
  • ...处理空的和非空的处理指令。

值得一提的有关限制的一些注意事项:

  1. 该模式用于浅层解析。也就是说,如果你还没有从字符串中删除其他可能包含文本的标记结构,这些文本又看起来像这样的处理指令(例如CDATA块或注释),那么模式将错误地匹配。
  2. 该模式与 XML声明匹配,该声明以&#34; <?xml&#34;开头。同样。这可以通过在打开&#34; <?&#34;之后不查找XML保留名称来更改。像#34; (?! [xX][mM][lL] (?: \?> | \s ) )&#34;。
  3. 这样的负向前瞻

    由于这些限制,可能值得考虑

    正则表达式的替代

    首先,使用PHP strip_tags来删除处理指令要容易得多。它也会删除其他标签和评论。这可能并不总是需要,它只是非常直接:

    strip_tags($str)
    

    更明确的是,正则表达式和strip_tags都使用PHP附带的XML解析器之一来去除处理指令。例如PHP的DOM扩展。它可以包装在一个函数中,以便轻松应用于字符串:

    dom_strip_pis($str)
    

    这样的示例性函数也适用于您使用保留名称&#34; xml&#34;的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解析器不会让您处理浅层解析。

答案 1 :(得分:0)

你非常接近 - 请注意&#39;?&#39;在收盘角括号前的最后:

<?xml:namespace prefix = o /?>

为了匹配它,你需要这个:

<?php
$clean=preg_replace('/<\?xml[^>]+\/\?>/im', '', $dirty);
?>