2016-11-12 41 views
1

を無視してPHPでDOMXPathを使うことの最大を持つXML属性を取得、私はXMLファイルがあります。名前空間

<Receipt Version="2.0" ReceiptDate="2012-08-30T23:10:05Z" CertificateId="A656B9B1B3AA509EEA30222E6D5E7DBDA9822DCD" xmlns="http://schemas.microsoft.com/windows/2012/store/receipt"> 
.... 
</Receipt> 

を、私はPHPでXPathをCertificateIdを取得しよう:Msftを持っているので

$doc = new DOMDocument(); 
$doc->loadXML($v); 
$xpath = new DOMXPath($doc); 
$query = 'string(/Receipt/@CertificateId)'; 
$id = $xpath->evaluate($query); 

$idは無効となりますこのリンクを放棄したので、ネームスペースにアクセスできません。すなわち、CertificateIdをネームスペースを無視して取得する必要があります(XMLから名前空間文字列を削除すると、コードは機能しますが、XMLを編集したくないです)。私はそれがlocal-name() XPath関数で行うことができます知っていますが、私はこれをPHPで行うことができますか?


は、ここで私はDOMからそれを読む方法は次のとおりです。

 $id = null; 
     if ($doc->childNodes->length > 0) 
     { 
      $root = $doc->childNodes->item(0); 
      if ($root->nodeName == 'Receipt') 
       $id = $root->attributes->getNamedItem('CertificateId')->nodeValue; 
     } 

このコードでは、名前空間を無視します。しかし、XPathを使ってこれを行う方法は?

+0

*「私はそれは、XPathの 'ローカル名()'関数によって行うことができます知っているが、私は、PHPでこれをどのように行うことができますか?」*あなたは* * 'ローカル名を使用することはできませんなぜ/どのように() 'PHPで? – har07

+0

これを行う方法がわかりませんでした。トリッキーな構文 – Tertium

答えて

1

XPath 2.0では、名前空間の部分にワイルドカード(string(//*:Receipt/@CertificateId))を使用することがあります。しかし、PHPは現在、私が知る限り、XPath 1.0のみを実装しています。

あなたが名前空間に登録するか:あなたも、特定の名前空間を言及したくない場合は、

$xpath->registerNamespace('x', 'http://schemas.microsoft.com/windows/2012/store/receipt'); 
$query = 'string(//x:Receipt/@CertificateId)'; 

や属性のみを選択する:

$query = 'string(//*/@CertificateId)'; 

をそれ以外の場合は、あなたがlocal-nameを使用するように強制されています:

$query = "string(//*[local-name(.) = 'Receipt']/@CertificateId)"; 
+0

いいえ、私はそれが私に何をチェックさせるか知りたくありません。私はちょうど無視したい。私の更新を参照してください。 – Tertium

+0

私はReceipt要素だけをチェックする必要があります。 // */@ CertificateIdは、try/Receipt/*/@ CertificateIdの要素のattr値を表示します。動作しません。そしてはい、PHPはxpath 2.0をサポートしていません – Tertium

+0

ありがとう、それは動作します!最も明白な構文ではなく、これはPHPのマニュアルにある可能性があります。 Btwは、1つの開始スラッシュでも機能します。 – Tertium

0

ここでは名前空間を無視する必要はありません。名前空間は既存のURLである必要はありません。彼らは世界的にユニークでなければなりませんURNs。多くの人が、自分が所有するドメインのURLを使用します。そのように競合する可能性はあまりありません。そしてそこにいくつかの文書を置くことができます。

ちょうどそれのための接頭辞を登録し、XPathの名前空間を使用するには:

$xml = <<<'XML' 
<Receipt 
    Version="2.0" 
    ReceiptDate="2012-08-30T23:10:05Z" 
    CertificateId="A656B9B1B3AA509EEA30222E6D5E7DBDA9822DCD" 
    xmlns="http://schemas.microsoft.com/windows/2012/store/receipt"> 
</Receipt> 
XML; 

$document = new DOMDocument(); 
$document->loadXml($xml); 
$xpath = new DOMXpath($document); 
$xpath->registerNamespace(
    'sr', 'http://schemas.microsoft.com/windows/2012/store/receipt' 
); 
var_dump(
    $xpath->evaluate('string(//sr:Receipt/@CertificateId)') 
); 

出力:あなたはドン場合

string(40) "A656B9B1B3AA509EEA30222E6D5E7DBDA9822DCD" 

例URN名前空間のためには、」rfc6321

ですXpathを使うのが好きです(想像できません)。ネームスペースを意識したDOMのメソッドとプロパティを使用できます。

$id = null; 
if ($document->childNodes->length > 0) { 
    $node = $document->childNodes->item(0); 
    if (
    $node->localName == 'Receipt' && 
    $node->namespaceURI == 'http://schemas.microsoft.com/windows/2012/store/receipt' 
) { 
    $id = $node->getAttributeNS(null, 'CertificateId'); 
    } 
} 
var_dump($id); 
+0

再び、私はこのバグの古いものに何があるか知りたいとは思わないが、スキップしないといくつかの属性が存在すると仮定している。その壊れた名前空間はほとんど正規表現を利用しました – Tertium

+0

名前空間は壊れていません。既存のURLである必要はありません。他の名前空間でも同じように動作します。 – ThW

+0

清算をありがとう – Tertium