2010-09-15 7 views
3

Cela commence à me faire chier vraiment mauvais. J'ai ce code XML:xPath ne trouve rien mais *

Mise à jour avec namespaces correct

<?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> 

Et ce code PHP:

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

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

J'ai largué seulement newXML $ et des tonnes acquis de données, mais la seulement xPath j'ai couru quoi que ce soit mais un tableau vide était "*"

Est-ce que "// ID" n'est pas censé trouver tous les nœuds ID dans le document? Pourquoi ça ne marche pas?

Merci

+0

Le problème est très probablement l'espace de noms ('xmlns: xsi'). Je ne sais pas comment aider encore plus, les compétences insuffisantes ': P' – Kobi

+0

Pas sûr, mais essayez de remplacer' xmlns' par 'ns'. (inspiré par [ce commentaire sur PHP.net] (http://nl2.php.net/manual/en/simplexmlelement.xpath.php#96153). – Lekensteyn

+3

Je ressemble probablement à un fanatique, mais à mon humble avis suppression des espaces de noms pour faire fonctionner les requêtes XPath est juste un hack XML qui est utilisé pour surmonter les défauts des outils de programmation ou l'incompétence du programmeur. Les espaces de noms sont un concept fondamental en XML. Toute personne qui va utiliser XML devrait apprendre à les comprendre. – jasso

Répondre

6

J'ai largué seulement newXML $ et obtenu tonnes de données, mais la seule xPath que j'ai course qui est retourné tout sauf un tableau vide était « * »

Alors, quel était retourné de var_dump($newXML->xpath("*"));? <Infringement>?

Si le problème est namespaces, essayez ceci:

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

Cela correspond à aucun élément du document dont le nom est 'ID', quel que soit l'espace de noms.

Mon truc fonctionne si je remplace tous "xmlns" avec "ns"

Attendez, quoi? Êtes-vous sûr de nous avoir montré tous les attributs liés au xmlns dans le document?

Mise à jour: La question a été modifiée pour montrer que le code XML a réellement une déclaration d'espace de noms par défaut.Cela explique le problème original: votre expression XPath sélectionne les éléments d'ID qui ne figurent dans aucun espace de noms, mais les éléments de votre document se trouvent dans l'espace de noms ACNS de movielabs, grâce à la déclaration d'espace de noms par défaut. La déclaration xmlns="http://www.movielabs.com/ACNS" sur un élément signifie "cet élément et tous les descendants qui n'ont pas de préfixe d'espace de nom (comme ID) sont dans l'espace de noms représenté par l'espace de noms URI 'http://www.movielabs.com/ACNS'." Donc, utilisez ma réponse local-name() ci-dessus pour ignorer les espaces de noms, ou utilisez la technique de jasso pour spécifier les ACNS de movielabs et l'utiliser comme prévu.

+0

'nom-local()' c'est alors. Mon script aura des tonnes de documents XML et je ne peux pas être sûr qu'ils auront tous le même espace de noms par défaut – Hubro

+0

@Codemonkey c'est une bonne solution. Si vous ne connaissez pas leur espace de noms par défaut mais qu'ils sont tous dans le même espace de noms (en utilisant éventuellement un préfixe d'espace de noms), vous pouvez toujours utiliser la méthode jasso, car le préfixe de votre script n'a pas à correspondre au préfixe. Document XML. Seul l'URI de l'espace de noms doit correspondre. Ou vous pouvez ignorer complètement les espaces de noms. – LarsH

0

Je ne suis pas bien versé dans l'API XML de PHP, mais je pense que le problème réside dans les espaces de noms. Selon le fonctionnement de cette méthode xpath, il se peut qu'elle recherche des éléments d'ID avec un espace de noms vide. Vos éléments d'ID héritent de leur espace de noms à partir de l'élément racine.

+0

Je ne comprends même pas un peu - désolé – Hubro

+0

L'ai-je mal interprété ou y avait-il un attribut xmlns sur l'élément Infringement? – Simon

+0

Il y avait, oui. Deux d'entre eux en fait. Mon truc fonctionne si je remplace tous les "xmlns" par "ns", mais n'y a-t-il pas moyen de * changer * le XML? – Hubro

8

L'élément racine de votre document XML semble avoir un espace de nom par défaut avec l'URI "http://www.movielabs.com/ACNS". Cela signifie que tous les éléments de votre document appartiennent à cet espace de noms. Le problème est que toutes les expressions XPath qui n'ont pas de préfixe d'espace de nommage recherchent des éléments qui n'appartiennent à aucun espace de noms. Pour rechercher des éléments (ou des attributs ...) à partir d'un certain espace de noms, vous devez enregistrer l'URI de l'espace de noms à un préfixe, puis utiliser ce préfixe dans votre expression XPath.

En cas de simpleXML de PHP, il est fait quelque chose comme ça

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

prefix peut être pratiquement tout texte, mais l'espace de nom URI doit correspondre exactement à celui utilisé dans votre document XML.

1

utiliser ceci pour tout espace de noms:

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

cela fonctionne dans XPath 2.0 mais pas dans 1.0. – LarsH

0

Vous avez un espace de noms XML défini dans l'élément de document (l'attribut xmlns="http://www.movielabs.com/ACNS"). L'espace de noms est l'URL http://www.movielabs.com/ACNS. Cela doit par une chaîne globalement unique (un URN). A cause de cela, les URL sont souvent utilisées. La chance que quelqu'un utilise votre domaine pour un espace de noms est très faible et vous pouvez mettre de la documentation à l'URL.

L'analyseur XML résout les espaces de noms. Le noeud obtient 4 propriétés.

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

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

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

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

$namespaceURI et $localName sont stables. Les deux autres dépendent du préfixe. Le préfixe est un alias pour l'espace de noms. L'espace de nom uri est long et complexe, il rendrait le XML beaucoup plus difficile à lire à écrire s'il était utilisé sur chaque élément/attribut. Mais vous pouvez interpréter les noeuds d'éléments tels que:

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

Ainsi, l'espace de noms est la seule chose qui définit ce que les nœuds signifient pas le préfixe/alias. Les préfixes peuvent être redéfinis sur un sous-élément. Xpath utilise le même concept avec un propre résolveur. Vous enregistrez vos propres préfixes pour un espace de noms. Peu importe comment les préfixes sont utilisés dans le XML, seul l'uri de l'espace de nom doit correspondre.

Dans DOM vous le faites sur l'instance 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, vous pouvez enregistrer l'espace de noms sur la 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] 
); 

TRUC: L'espace de noms par défaut est utilisé uniquement pour les éléments, les attributs sont dans la « non/espace vide » à moins qu'ils aient un préfixe.