【问题标题】:looping through all children of element with domdocument and extract text-content使用 domdocument 循环遍历元素的所有子元素并提取文本内容
【发布时间】:2014-11-02 03:34:18
【问题描述】:

这是我尝试解析的 xml 文件(odt-file)的结构:

<office:body>
    <office:text>
        <text:h text:style-name="P1" text:outline-level="2">Chapter 1</text:h>
            <text:p text:style-name="Standard">Lorem ipsum. </text:p>

            <text:h text:style-name="Heading3" text:outline-level="3">Subtitle 2</text:h>
                <text:p text:style-name="Standard"><text:span text:style-name="T5">10</text:span><text:span text:style-name="T6">:</text:span><text:s/>Text (100%)</text:p>
                    <text:p text:style-name="Explanation">Further informations.</text:p>
                <text:p text:style-name="Standard">9.7:<text:s/>Text (97%)</text:p>
                    <text:p text:style-name="Explanation">Further informations.</text:p>
                <text:p text:style-name="Standard"><text:span text:style-name="T9">9.1:</text:span><text:s/>Text (91%)</text:p>
                    <text:p text:style-name="Explanation">Further informations.</text:p>
                    <text:p text:style-name="Explanation">More furter informations.</text:p>
    </office:text>
</office:body>

使用 XML-Reader 我是这样做的:

while ($reader->read()){ 
    if ($reader->nodeType == XMLREADER::ELEMENT && $reader->name === 'text:h') { 
        if ($reader->getAttribute('text:outline-level')=="2") $html .= '<h2>'.$reader->expand()->textContent.'</h2>';
    }
    elseif ($reader->nodeType == XMLREADER::ELEMENT && $reader->name === 'text:p') { 
        if ($reader->getAttribute('text:style-name')=="Standard") {
            $html .= '<p>'.$reader->readInnerXML().'<p>';
        }
        else if {
            // Doing something different
        }
    }
}
echo $html;

现在我想对 DOMDocument 做同样的事情,但我需要一些语法方面的帮助。如何遍历所有办公室的孩子:文本?在遍历所有节点时,我会通过 if/else 检查要做什么(文本:h 与文本:p)。

我还需要用空格替换每个 text:s(如果 text:p 中有这样的元素)...

$reader = new DOMDocument();
$reader->preserveWhiteSpace  = false;
$reader->load('zip://content.odt#content.xml');

$body = $reader->getElementsByTagName( 'office:text' )->item( 0 );
foreach( $body->childNodes as $node ) echo $node->nodeName . PHP_EOL;

或者循环遍历所有文本元素会更聪明吗?如果是这种情况,仍然是问题,如何做到这一点。

$elements = $reader->getElementsByTagName('text');
foreach($elements as $node){
    foreach($node->childNodes as $child) {
        echo $child->nodeName.': ';
        echo $child->nodeValue.'<br>';
        // check for type...
    }
}

【问题讨论】:

    标签: php xml domdocument


    【解决方案1】:

    使用 DOMDocument 最简单的方法之一就是借助 DOMXPath

    从字面上理解你的问题:

    如何循环遍历所有 office:text 子级?

    这可以表示为XPath expression

    //office:text/child::node()
    

    但是您在这里使用了一些错误的措辞。不仅是所有的孩子,还有孩子的孩子等等等等——这就是所有的后代

    //office:text/descendant::node()
    

    或者用缩写语法:

    //office:text//node()
    

    比较:XPath to Get All ChildNodes and not the Parent Node

    为了在 PHP 中循环,您需要为 office 前缀注册命名空间,然后使用 foreach 循环 xpath 结果: $xpath = new DOMXPath($reader); $xpath->registerNamespace('office', $xml_namespace_uri_of_office_namespace);

    $descendants = $xpath->query('//office:text//node()');
    foreach ($descendants as $node) {
        // $node is a DOMNode as of DOMElement, DOMText, ...
    }
    

    XPath 不是一般的,但在 PHP 的基于 libxml 的库中确实按文档顺序返回节点。这就是您要查找的顺序。

    比较:XPath query result order

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-05-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-04-29
      • 1970-01-01
      相关资源
      最近更新 更多