2011-09-12 49 views
0

我從第三方解析Xml時遇到問題;有幾個不同版本的XML,它們發送的是重疊的命名空間;XML :: LibXML - 查找(並註冊)文檔中使用的名稱空間


版本1個

富= 「甕:bar.org/version-1」

遠= 「甕:gle.org/version-1」


版本2

foo =「bar:a.org/version-2」

遠=「GLE:a.org/version-2」


以前(那時我纔不得不處理一個版本),我會從一個硬編碼的哈希註冊的命名空間,如下所示:

#!/usr/bin/perl 

use strict; 
use XML::LibXML ; 

my $cfg->{namespace} = { 
    foo=>"urn:bar.org/version-1", 
    far=>"urn:gle.org/version-1", 
}; 

my $parser = XML::LibXML->new({recover => '1'}); 

my $doc = $parser->parse_string($inputHash->{$key}->{xml}); 

my $xc = XML::LibXML::XPathContext->new($doc->documentElement()); 

for my $ns (keys %{$cfg->{namespace}}) 
{ 
    $xc->registerNs($ns => $cfg->{namespace}->{$ns}); 
} 

顯然,這將只對第1版工作..

有沖刷的libxml文檔,但不能找到一種方式來提取在文檔中使用的命名空間並註冊;任何人都可以給我一個指針嗎?

僞DOC:

<?xml version="1.0"?> 
<foo:Parent xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:foo="bar:a.org/version-2"> 
    <far:Child xmlns:gle="gle:a.org/version-2"> 
    {horrific structure with more ns declarations all of which need registering} 
    </far:Child> 
</foo:Parent> 
+0

如果命名空間不可預知,那麼這是一個瘋狂的模式!你不應該處理這個。 – ikegami

+0

我知道,但不應該不是一種選擇。這是一家大型電信公司的工作 - 對他們感到羞恥! – beresfordt

+0

是的,我只是同情。請注意,XPath'name(「moo」)'將匹配來自任何名稱空間的元素'moo'。在查找名稱空間要識別的元素時,它可能很有用。 – ikegami

回答

6

都會響起的this answer,我會使用//namespace::* XPath表達式找到的命名空間。試試這個代碼示例,看看它是否有幫助:

use strict; 
use warnings; 
use XML::LibXML; 

my $cfg; 
my $xml = XML::LibXML->load_xml(location => <your xml>); 
foreach my $node ($xml->findnodes('//namespace::*')) { 

    $cfg->{namespace}{$node->getLocalName()} = $node->getValue(); 
} 

這應該填充您的散列與你需要的。另外,這個XPath表達式並不總是被支持的。我使用LibXML 1.70和dll 20703版測試了它,它對我很有幫助。

+0

謝謝 - 這適用於在父標籤中聲明的名稱空間,但不會在樹中聲明更深的名稱空間。將通過該線程,看看我能從中得到什麼。用psuedo xml更新問題:) – beresfordt

+0

ahha - 將findnodes表達式改爲:'// */namespace :: *'就可以了!非常感謝 - 你已經救了我一些恐怖:) – beresfordt

0

我想嘗試XML ::的libxml ::節點:: lookupNamespaceURI,即

$cfg->{namespace}->{foo} = $node->lookupNamespaceURI("foo"); 

一些節點足夠深,使其具有聲明。要使用的最簡單的節點是文檔,但除非在頂部聲明瞭命名空間,否則這將不起作用;最常用的方法將通過所有節點,並根據您的應用程序邏輯處理相同前綴被重用於不同名稱空間的情況...

+0

謝謝,但這仍然需要聲明'foo''bar'等 - 我寧願遠離硬編碼任何東西,所以我不需要重新訪問這個! – beresfordt

+0

那麼,你可以從節點名稱中獲得前綴 - 只需將它們分成':'即可。但我不認爲有可能使腳本處理其輸入格式的每一個未來變化... – vbar

0

您遍歷樹尋找名稱空間,直到找到一個,說的getElementsByTagName使用或一些這樣的

#!/usr/bin/perl -- 

use strict; 
use warnings; 

use XML::Twig; 

my $xml = <<'__XML__'; 
<?xml version="1.0"?> 
<!-- initially, the default namespace is "books" --> 
<book xmlns='urn:loc.gov:books' 
     xmlns:isbn='urn:ISBN:0-395-36341-6'> 
    <title>Cheaper by the Dozen</title> 
    <isbn:number>1568491379</isbn:number> 
    <notes> 
     <!-- make HTML the default namespace for some commentary --> 
     <p xmlns='urn:w3-org-ns:HTML'> 
      This is a <i>funny</i> book! 
     </p> 
    </notes> 
</book> 
__XML__ 

{ 
    my $t = XML::Twig->new(
     start_tag_handlers => { 
      _all_ => sub { 
       my $tag = $_[1]->tag; 
       my $nsp = $_[1]->ns_prefix||''; 
       print "$tag => $nsp\n"; 
       print map { 
        join ' ', 
         "\t", $_,' => ', $_[1]->att($_), "\n" 
        } grep /xmlns/ , $_[1]->att_names ; 
      }, 
     }, 
    ); 
    $t->parse($xml); 
} 
__END__ 
book => 
     xmlns => urn:loc.gov:books 
     xmlns:isbn => urn:ISBN:0-395-36341-6 
title => 
isbn:number => isbn 
notes => 
p => 
     xmlns => urn:w3-org-ns:HTML 
i => 
+0

謝謝 - 我會研究這個模塊,如果我不能得到任何東西與LibXML – beresfordt

相關問題