【问题标题】:How to extract certain tags and replace others from XML with SimpleXML如何从 XML 中提取某些标签并用 SimpleXML 替换其他标签
【发布时间】:2012-01-10 12:26:41
【问题描述】:

我正在用 PHP 编写自己的博客,我希望能够在 Markdown 中写帖子以 HTML 显示结果,我还需要用 HTML 做一些自定义的事情。

有一个简单的脚本可以将 Markdown 转换为 HTML,但是一旦完成,我需要对 HTML 做一些事情:

  1. 我需要使用 htmlentities() 函数替换 pre 标记内的所有 HTML 符号。 (在我的博客中,我发布了包含 HTML 在内的代码,我只想显示这个 HTML,而不是在浏览器中解析它)。

  2. 我需要提取所有纯文本,以便在结尾处创建不包含图像标签或半标签(或 pre 中的代码片段)的摘录。

我认为使用以下代码可以解决问题 2:

$xml = new SimpleXMLElement('<xml>' . $html . '</xml>');

$xml 现在看起来像:

<xml>
  <p>some random text</p>
  <img src='image.jpg'>
  <p>some random text</p>
</xml>

这会提取所有文本:

foreach($xml->{'p'} as $p){
echo $p . '<hr>';
}

这可行,但是我也希望它包含在 ul 和 ol 中找到的所有文本(与它们在 XML 中出现的顺序相同。我已经搜索了一种方法来遍历 $xml 的所有子级,但我找不到如何检查元素是 p、ul 还是 ol。

而且我找不到解决问题 1 的方法,因为我不知道如何替换 XML 对象中的内容,但保持其他所有内容不变。 (或者我是否遗漏了一些非常明显的东西?)

【问题讨论】:

标签: php xml parsing text replace


【解决方案1】:

经过大量搜索后,我无法准确找到我正在寻找的使用 XML 解析的内容,此外我还需要一些其他功能。我用 REGEX 解决了这个问题,因为所有的 HTML 都是由我生成的。

所以这里提供的解决方案解决了我原来的问题+一些问题。

这个函数接受一段内容(字符串)并返回几个字符串:

  • md = 与 pre 中带有尖括号的内容更改为它们的 html 实体相同(我写了关于 HTML 的博客,但在我的 edit post 屏幕中,我不希望 pre 中的 html 被解析.
  • html = pre 之外的所有内容都是 Markdown 的,pre 中的每个 htmlchar 都更改为它们的 html 实体。
  • 摘录 = 文本缩小到接近 300 个字符,没有任何前置标记(或这些标记的内容),没有降价语法或 html 标记。
  • meta = 与 160 个字符的摘录相同。

    function prepareContent($content) {
    
        // I use this instead of htmlentities for the plain text, this prevents HTML to be parsed inside the edit screen
        // all HTML is served with htmlentities instead
        function removeAngleBrackets($str) {
            $str = str_replace('<','&lt;',$str);
            $str = str_replace('>','&gt;',$str);
            return $str;
        }
    
        $segments = preg_split('/(<\/?pre.*?>)/', $content, -1, PREG_SPLIT_DELIM_CAPTURE);
    
        // STATE MACHINE
        // borrowed from: http://stackoverflow.com/questions/1278491/howto-encode-texts-outside-the-pre-pre-tag-with-htmlentities-php#answer-1278575
    
        // this breaks when I nest pre's in pre's (unless I escape the <pre> myself), could be fixed though
    
        // $state = 0 if outside of a pre
        // $state = 1 if inside of a pre
        $state = 0;
    
        $plaintext = '';
        $html = '';
        $preless = '';
    
        // $html, $plaintext and $preless are all written in here
        foreach ($segments as &$segment) {
            if ($state == 0) {
                if (preg_match('#<pre[^>]*>#i',$segment)) {
                    //this is the pre opening tag
                    $state = 1; 
                    $html .= $segment;
                    $plaintext .= $segment;
                } else {
                    //this is outside the pre tag
                    $plaintext .= $segment;
                    $markdown = Markdown($segment);
                    $html .= $markdown;
                    $preless .= $markdown;
                }
            } else if ($state == 1) {
                if ($segment == '</pre>') {
                    //this is the pre closing tag
                    $state = 0;
                    $html .= $segment;
                    $plaintext .= $segment;
                } else {
                    //this is inside the pre tag
                    $plaintext .= removeAngleBrackets($segment);
                    // first encode &gt; to > so I can re encode it together with other chars
                    // else we get double encoding like: $amp;gt;
                    $enti = html_entity_decode($segment);
                    $html .= htmlspecialchars($enti, ENT_QUOTES);
                }
            }
        }
    
        $arr['html'] = SmartyPants($html);
        $arr['md'] = $plaintext;
    
        //                      the excerpt & meta
    
        // remove all html tags (markdown is already converted to HTML)
        $tagless = strip_tags($preless);
    
        function shrinkText($str, $limit) {
            $strlen = strlen($str);
            if($strlen > $limit) {
                $pos = strpos($str, ' ', $limit);
                if($strlen > $pos) {
                    $result = substr($str,0,$pos);
                }
            }
            return $result ? $result : $str;
        }
    
        // I need to smartypants the excerpt to
        $excerpt = shrinkText($tagless, 275)  . ' (...)';
        $arr['excerpt'] = SmartyPants($excerpt);
    
        $arr['meta'] = shrinkText($tagless, 160);
    
        return $arr;
    }
    

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-06-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-22
    • 2021-07-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多