2014-11-02 46 views
0

這是一個XML文件(ODT文件)的結構,這是我嘗試解析:循環通過與DOM文檔元素的所有孩子,並提取文本的內容

<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閱讀器我做是這樣說的:

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; 

現在我想這樣做同樣的事情與DOM文檔,但我需要一些幫助的語法。我如何循環辦公室的所有孩子:文字?當循環遍歷所有節點時,我會通過if/else來檢查要做什麼(文本:h與text:p)。

我還需要更換所有的文本:S(如果在文本這樣的元素: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... 
    } 
} 

回答

0

一個最簡單的方法來做到這一點與DOM文檔是與DOMXPath幫助。

考慮您的問題從字面上:

我如何遍歷的辦公室裏所有的孩子:文字?

這可以表示爲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前綴的名稱空間,然後你遍歷中的XPath與導致10: $ 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