2011-01-20 50 views
2

我讀通過第三方應用程序生成一個XML文件,包含以下內容的XML文件中提取HTML:從使用SimpleXML

<Cell> 
    <Comment ss:Author="Mark Baker"> 
     <ss:Data xmlns="http://www.w3.org/TR/REC-html40"><B><Font html:Face="Tahoma" html:Size="8" html:Color="#000000">Mark Baker:</Font></B><Font html:Face="Tahoma" html:Size="8" html:Color="#000000">&#10;Comment 1 - No align</Font></ss:Data> 
    </Comment> 
</Cell> 

我試圖做的是從訪問原始數據Cell-> Comment-> Data元素或者「原樣」或者作爲(X)HTML標記的實際塊(最好是後者)。

if (isset($cell->Comment)) { 
    echo 'comment found<br />'; 
    $commentAttributes = $cell->Comment->attributes($namespaces['ss']); 
    if (isset($commentAttributes->Author)) { 
     echo 'Author: ',(string)$commentAttributes->Author,'<br />'; 
    } 
    $commentData = $cell->Comment->children($namespaces['ss']); 
    var_dump($commentData); 
    echo '<br />'; 
} 

給我:

comment found 
Author: Mark Baker 
object(SimpleXMLElement)#130 (2) { ["@attributes"]=> array(1) { ["Author"]=> string(10) "Mark Baker" } ["Data"]=> object(SimpleXMLElement)#129 (0) { } } 

if (isset($cell->Comment)) { 
    echo 'comment found<br />'; 
    $commentAttributes = $cell->Comment->attributes($namespaces['ss']); 
    if (isset($commentAttributes->Author)) { 
     echo 'Author: ',(string)$commentAttributes->Author,'<br />'; 
    } 
    $commentData = $cell->Comment->Data->children(); 
    var_dump($commentData); 
    echo '<br />'; 
} 

給我:

comment found 
Author: Mark Baker 
object(SimpleXMLElement)#129 (2) { ["B"]=> object(SimpleXMLElement)#118 (1) { ["Font"]=> string(11) "Mark Baker:" } ["Font"]=> string(21) " Comment 1 - No align" } 

不幸的是,simplexml的似乎是把整個元素作爲一系列XML的節點。我確信我應該能夠得到這個沒有複雜循環的原始數據,或者將元素饋送到DOM Parser;也許使用xmlns =「http://www.w3.org/TR/REC-html40」命名空間來乾淨地提取這個,但我不知道如何。

任何幫助表示讚賞。 XML數據的

更復雜的例子:

<Cell> 
    <Comment ss:Author="Mark Baker"> 
     <ss:Data xmlns="http://www.w3.org/TR/REC-html40"> 
      <B><Font html:Face="Tahoma" html:Size="8" html:Color="#000000">Mark Baker:</Font></B><Font html:Face="Tahoma" html:Size="8" html:Color="#000000">&#10;</Font><B><Font html:Face="Tahoma" x:Family="Swiss" html:Size="8" html:Color="#000000">Rich </Font><U><Font html:Face="Tahoma" x:Family="Swiss" html:Size="8" html:Color="#FF0000">Text </Font></U><Font html:Face="Tahoma" x:Family="Swiss" html:Size="8" html:Color="#000000">Comment</Font></B><Font html:Face="Tahoma" html:Size="8" html:Color="#000000"> Center Aligned</Font> 
     </ss:Data> 
    </Comment> 
</Cell> 
+1

你有過XML輸出控制?你的'`標籤的內容不應該用`CDATA`標籤包裝嗎? – drudge 2011-01-20 18:41:29

+0

它應該在CDATA標籤中。不幸的是,我對XML輸出沒有任何控制......除非生產該軟件的公司決定解僱史蒂夫鮑爾默並且用自己重新安排他:( – 2011-01-20 20:51:02

回答

0

我已經走了與時間是一個快速和骯髒的解決方案。從長遠來看,我將切換到使用XMLReader(出於所有提到的原因)......我現在沒有時間重寫所有現有的simpleXML代碼。

我已經有:

$node = $cell->Comment->Data->asXML(); 
$comment = substr($node,49,-10); 
$comment = strip_tags($comment); 

雖然我寧願保持HTML標記,這將需要額外的工作,所以我乾脆剝離所有的標記留下我與純文本(這是關鍵因素)。雖然這是一個遠非完美的解決方案,但它完成了我所需要的工作(目前),並且我可以移動到「待辦事項」列表中的下一個項目,已經添加了一個新項目「使用XMLReader重寫」到該列表。

感謝您的幫助。當我正在進行重寫時,我一定會重新訪問這個線程。

1

如果<ss:Data>元素內的HTML被認爲是一個字符串,它必須被纏繞成CDATA section作爲評價已經暗示

$xml = <<< XML 
<Cell> 
    <Comment ss:Author="Mark Baker"> 
     <ss:Data xmlns="http://www.w3.org/TR/REC-html40"> 
      <![CDATA[ 
       <B><Font html:Face="Tahoma" … html:Color="#000000"> 
      ]]> 
     </ss:Data> 
    </Comment> 
</Cell> 
XML; 
libxml_use_internal_errors(TRUE); 
$cell = simplexml_load_string($xml); 
echo $cell->Comment->Data; 

如果它不在CDATA部分,它將被視爲節點。然後,您將查找<ss:Data>的內部XML以將其作爲原始XML。不幸的是,SimpleXml和DOM都沒有一種原生的方式直接獲取。你必須使用用戶級的實現。

innerXml的Userland實現通常會迭代所有子節點並連接其原始XML。或者他們轉儲整個樹和字符串替換根節點。或者他們創建一個片段或將節點導入到另一個文檔中。

我不知道有任何其他方式來做到這一點。不知道這是否可能與XSLT。儘管如此,XMLReader有一個readInnerXML方法。

+0

理論上,XMLReader readInnerXML()方法應該允許我這樣做。 ..如果我要從simpleXML切換到XMLReader這可能有點工作,因爲這只是一個更復雜文件的一小部分另一種選擇可能是使用preg_replace(或類似)來包裝我的ss:數據「字符串」在解析之前在CDATA中,但是這些文件可能是幾MB,所以我不確定會對性能產生什麼影響 – 2011-01-20 21:28:49

2

如果您的實施是使用DOM,我相信你可以做到以下幾點:

//given $node is <ss:data> 

$frag = $node->ownerDocument->createDocumentFragment(); 
foreach($node->childNodes as $child){ 
    $frag->appendChild($child->cloneNode(true)); 
} 
$string = $node->ownerDocument->saveXML($frag); 
0

所以我知道你的問題已經來臨,但我有同樣的問題,我不得不弄清楚我是如何處理它。爲了後代,我是這麼來的。

如果你只接受(X)HTML:

$data = str_replace('<?xml version="1.0"?>','',$xmlNode->asXML()); 

如果你認爲有人要把XML和你與OK,你只需要殺掉第一個,自動生成的XML標籤:

$data = preg_replace('/^<\?xml version="1.0"\?\>\n/', '',$xmlNode->asXML()); 

所以,你的代碼應該是這樣的:

if (isset($cell->Comment)) { 
    echo 'comment found<br />'; 
    $commentAttributes = $cell->Comment->attributes($namespaces['ss']); 
    if (isset($commentAttributes->Author)) { 
     echo 'Author: ',(string)$commentAttributes->Author,'<br />'; 
    } 
    $commentData = str_replace('<?xml version="1.0"?>','',$cell->Comment->Data->asXML()); 
    echo $commentData; 
    echo '<br />'; 
}