【问题标题】:Remove Processing Instruction (<?xml tags and content) from XML String从 XML 字符串中删除处理指令(<?xml 标记和内容)
【发布时间】:2015-06-07 17:49:25
【问题描述】:

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

<?xml:namespace prefix = o /?>

如何使用 PHP 和正则表达式从字符串中删除该标签和类似标签?

我试过了:

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

【问题讨论】:

    标签: php regex xml string processing-instruction


    【解决方案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
    

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

    • ... 正确考虑结束顺序 ("?&gt;")。特别是在处理指令中可以允许使用“&gt;”。
    • ...不需要限制处理指令的名称只能以“xml”开头。
    • ...它实际上是在寻找一个名称作为开头序列的一部分。
    • ...处理空和非空处理指令。

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

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

    由于这些限制,也许值得考虑

    正则表达式的替代方法

    首先,使用 PHP 的strip_tags 来剥离处理指令会容易得多。它也会删除其他标签和 cmets。这可能并不总是想要的,它真的很简单:

    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 解析器不会让您处理浅层解析。

    【讨论】:

      【解决方案2】:

      你非常接近 - 注意“?”在右尖括号之前的最后:

      <?xml:namespace prefix = o /?>
      

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

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

      【讨论】:

      • 当有附上的评论告诉我如何在未来改进我的答案时,我很感激投反对票。如果没有评论,那么您的投票对 SO 社区没有帮助...
      • 谢谢,我正在测试。我没有投反对票,如果可行,我投票给你。谢谢你的努力彼得:)
      猜你喜欢
      • 2017-08-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-01-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多