2010-09-15 156 views
3

這開始讓我感到非常不好。我有這樣的XML代碼:xPath找不到任何東西,但*

用正確的命名空間

<?xml version="1.0" encoding="utf-8"?> 

<Infringement xsi:schemaLocation="http://www.movielabs.com/ACNS http://www.movielabs.com/ACNS/ACNS2v1.xsd" xmlns="http://www.movielabs.com/ACNS" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> 
    <Case> 
    <ID>...</ID> 
    <Status>Open</Status> 
    </Case> 
    <Complainant> 
    <Entity>...</Entity> 
    <Contact>...</Contact> 
    <Address>...</Address> 
    <Phone>...</Phone> 
    <Email>...</Email> 
    </Complainant> 
    <Service_Provider> 
    <Entity>...</Entity> 
    <Address></Address> 
    <Email>...</Email> 
    </Service_Provider> 
    <Source> 
    <TimeStamp>...</TimeStamp> 
    <IP_Address>...</IP_Address> 
    <Port>...</Port> 
    <DNS_Name></DNS_Name> 
    <Type>...</Type> 
    <UserName></UserName> 
    <Number_Files>1</Number_Files> 
    <Deja_Vu>No</Deja_Vu> 
    </Source> 
    <Content> 
    <Item> 
     <TimeStamp>...</TimeStamp> 
     <Title>...</Title> 
     <FileName>...</FileName> 
     <FileSize>...</FileSize> 
     <URL></URL> 
    </Item> 
    </Content> 
</Infringement> 

更新,此PHP代碼:

<?php 
    $data = urldecode($_POST["xml"]); 
    $newXML = simplexml_load_string($data); 

    var_dump($newXML->xpath("//ID")); 
?> 

我甩了只$ newXML,並得到噸的數據,但只有xPath我運行,返回任何東西,但空數組是「*」

是不是「ID」應該找到文檔中的所有ID節點?爲什麼它不工作?

感謝

+0

問題很可能是命名空間('xmlns:xsi')。不知道如何進一步幫助,但不足的技能':P' – Kobi 2010-09-15 16:19:00

+0

不確定,但嘗試用'ns'替換'xmlns'。 (受[此PHP.net上的此評論]啓發(http://nl2.php.net/manual/en/simplexmlelement.xpath.php#96153)。 – Lekensteyn 2010-09-15 16:26:48

+3

我可能聽起來像一個狂熱但恕我直言刪除命名空間,使XPath查詢的工作僅僅是用來克服任何的編程工具的缺陷或程序員的無能XML打破黑客。命名空間是XML中的一個基本概念。任何想使用XML的人都應該學會理解它們。 – jasso 2010-09-15 16:43:54

回答

6

我甩了只$ newXML並得到 噸的數據,但唯一的XPath我 傳回任何東西,但一個 空數組運行是「*」

那又是什麼從var_dump($newXML->xpath("*"));返回? <Infringement>

如果問題是命名空間,試試這個:

var_dump($newXML->xpath("//*[local-name() = 'ID']")); 

這將他的名字是「ID」文檔中的任何元素匹配,無論命名空間。

我的東西的作品,如果我全部更換 「的xmlns」 與 「NS」

等等,什麼?您確定您向我們展示了文檔中所有與xmlns相關的屬性嗎?

更新: 該問題被編輯,以表明XML確實有一個默認的命名空間聲明。這解釋了原始問題:由於默認的名稱空間聲明,XPath表達式選擇了沒有名稱空間的ID元素,但文檔中的元素位於movielabs ACNS名稱空間中。

元素上的聲明xmlns="http://www.movielabs.com/ACNS"意味着「此元素和所有沒有名稱空間前綴(如ID)的後代位於名稱空間URI'http://www.movielabs.com/ACNS'所表示的名稱空間中」。 (除非介入的後代有不同的默認命名空間聲明,這將陰影在這一個。)

所以用我上面的local-name()答案忽略的命名空間,或者使用學生支援機構的技術來指定movielabs ACNS,並以此爲意。

+0

'local-name()'然後。我的腳本將會得到大量的XML文檔,並且我不能確定它們都具有相同的默認命名空間 – Hubro 2010-09-15 17:03:17

+0

@Codemonkey,這是一個很好的解決方案。如果你不知道它們的默認命名空間,但它們都在同一個命名空間中(可能使用命名空間前綴),你仍然可以使用jasso的方法,因爲腳本中的前綴不必與XML文檔。只有名稱空間URI必須匹配。或者你可以完全忽略名稱空間。 – LarsH 2010-09-15 17:25:10

0

我不是很精通PHP的XML API,但我懷疑問題出在命名空間。根據xpath方法的工作原理,它可能會搜索具有空名稱空間的ID元素。您的ID元素從根元素繼承其名稱空間。

+0

我甚至沒有稍微理解 - 對不起 – Hubro 2010-09-15 16:20:02

+0

我誤讀了它還是曾經在侵權元素上使用過xmlns屬性? – Simon 2010-09-15 16:21:56

+0

有,是的。其中兩個。如果我用「ns」替換所有的「xmlns」,但我的東西能夠正常工作,但是沒有辦法改變* XML? – Hubro 2010-09-15 16:26:46

8

您的XML文檔的根元素似乎具有URI爲「http://www.movielabs.com/ACNS」的默認名稱空間。這意味着文檔中的所有元素都屬於該名稱空間。問題是沒有名稱空間前綴的所有XPath表達式都在搜索不屬於任何名稱空間的元素。要從某個名稱空間搜索元素(或屬性...),您需要將名稱空間URI註冊爲某個前綴,然後在您的XPath表達式中使用此前綴。

在PHP的SimpleXML的情況下,它做了這樣的事情

$newXML = simplexml_load_string($data); 
$newXML->registerXPathNamespace('prefix', 'http://www.movielabs.com/ACNS'); 
var_dump($newXML->xpath("//prefix:ID")); 

prefix可以是幾乎任何文字,但空間URI必須與您的XML文檔中使用的一個相匹配。

1

使用這種用於任何命名空間:

var_dump($newXML->xpath("//*:ID")); 
+0

這適用於XPath 2.0,但不適用於1.0。 – LarsH 2010-09-16 02:37:29

0

你必須在文檔元素定義的XML命名空間(該xmlns="http://www.movielabs.com/ACNS"屬性)。命名空間是URL http://www.movielabs.com/ACNS。這必須由一個全球唯一的字符串(一個URN)。由於這些URL經常被使用。有人使用你的域名作爲命名空間的可能性非常低,你可以在URL處添加一些文檔。

XML解析器解析名稱空間。該節點獲得4個屬性。

<Infringement xmlns="http://www.movielabs.com/ACNS"/>

$namespaceURI => http://www.movielabs.com/ACNS 
$localName => Infringement 
$prefix => 
$nodeName => Infringement 

對於<movie:Infringement xmlns:movie="http://www.movielabs.com/ACNS"/>

$namespaceURI => http://www.movielabs.com/ACNS 
$localName => Infringement 
$prefix => movie 
$nodeName => movie:Infringement 

$namespaceURI$localName是穩定的。另外兩個取決於前綴。前綴是名稱空間的別名。命名空間uri很長且很複雜,如果在每個元素/屬性上使用XML,讀取和寫入會變得更加困難。但是,你能解釋像元素節點:

{http://www.movielabs.com/ACNS}:Infringement 

所以命名空間的一兩件事,它定義了節點的意思是,沒有前綴/別名。前綴可以在子元素上重新定義。

<foo xmlns="urn:foo"><bar xmlns="urn:bar"/></foo> 

Xpath對自己的解析器使用相同的概念。您爲一個名稱空間註冊自己的前綴。因此,在XML中如何使用前綴並不重要,只有名稱空間uri必須匹配。

在DOM這樣做的DOMXPath實例:

$dom = new DOMDocument(); 
$dom->loadXml($xml); 
$xpath = new DOMXpath($dom); 
$xpath->registerNamespace('movie', 'http://www.movielabs.com/ACNS'); 

var_dump(
    $xpath->evaluate('string(/movie:Infringement/movie:Case/movie:ID)') 
); 

SimpleXML中,你可以註冊上的SimpleXMLElement的命名空間。

$element = simplexml_load_string($xml); 
$element->registerXpathNamespace('movie', 'http://www.movielabs.com/ACNS'); 
var_dump(
    (string)$element->xpath('/movie:Infringement/movie:Case/movie:ID')[0] 
); 

提示:默認命名空間僅用於元素,屬性是「無/空命名空間」,除非他們有一個前綴。

相關問題