php5でsimpleXMLを使っているのですが、名前空間の接頭辞のついた属性を取得する方法がわかりません。


<document>
<note ns:data="foo"></note>
</document>

こんな感じのイメージで"foo"を取得して配列に落とし込みたいのです。どなたかお知恵をいただけませんでしょうか。

回答の条件
  • URL必須
  • 1人10回まで
  • 登録:
  • 終了:2008/02/13 17:45:37
※ 有料アンケート・ポイント付き質問機能は2023年2月28日に終了しました。

ベストアンサー

id:tezcello No.3

回答回数460ベストアンサー獲得回数69

ポイント26pt

フローを示すだけではアレなんで...

$str = <<< EOL
<?xml version="1.0" encoding="UTF-8"?>
<docs xmlns:ns="http://hoge/fuga/">
<document>
<note ns:data="foo">abcde</note>
</document>
<document>
<note ns:data="hoo">edcba</note>
</document>
<document>
<note data="poo">123</note>
</document>
<document>
<note ns:data="boo">abcde</note>
</document>
</docs>
EOL;

$prefix = ''; $ns = '';

// 接頭辞や名前空間が既知なら上で定義すれば下3行は不要
if (preg_match('/xmlns:([-\w.]+)="(.+?)"/', $str, $tmp)){
  $prefix = $tmp[1]; $ns = $tmp[2];
}

preg_match_all('/\s'.$prefix.':([-\w.]+)="(.*?)"/', $str, $tmp);

var_dump($tmp[2]);

// simplexml での処理が必要ならこの先も
//$xml = simplexml_load_string($str);
//$xml->registerXPathNamespace('namespace', $ns);
//$res = $xml->xpath('//note[@namespace:data="foo"]');
//var_dump($res);
// 次の行が得られる
// array(1) { [0]=>  object(SimpleXMLElement)#2 (1) { [0]=>  string(5) "abcde" } }

array(3) { [0]=> string(3) "foo" [1]=> string(3) "hoo" [2]=> string(3) "boo" }

http://jp.php.net/manual/ja/function.preg-match-all.php

id:hiroshimo

回答ありがとうございます。非常にためになりました。少し質問のしかたがまずかったように思うので再度提示させていただきたいと思います。

<document>

<note data="foo">A</note>

<note data="bar">B</note>

</document>

うえのようなXMLがあったとして、AとかBを取り出そうとしたらこうですよね?

foreach ($xml as $document) {

echo $document->note, '
';

}

fooとかbarを取り出そうとしたら、こうですよね。

foreach ($xml as $document) {

echo $document->note[data], '
';

}

これをしたいのですが、dataにns:という接頭辞が付いているとうまくいきません。

foreach ($xml as $document) {

echo $document->note[ns:data], '
';

}

というようなことを解決したいのですが・・・。どうしたらいいのでしょう?

2008/02/13 14:40:31

その他の回答2件)

id:hatettyo No.1

回答回数23ベストアンサー獲得回数2

ポイント27pt
$sample = array();
$data = @simplexml_load_file(XMLのURL);
$sample[] = $data->document->note;

こうゆう事でしょうか。

documentが複数ある場合は

$sample = array();
$data = @simplexml_load_file(XMLのURL);
foreach($data->document as $value){
    $sample[] = $value->note;
}

という感じですかね。

http://q.hatena.ne.jp/1201158240

id:tezcello No.2

回答回数460ベストアンサー獲得回数69

ポイント27pt

名前空間が指定されている属性値を指定して取出したいという事でしょうか?

$str = <<< EOL
<?xml version="1.0" encoding="UTF-8"?>
<docs xmlns:ns="http://hoge/fuga/">
<document>
<note ns:data="foo">abcde</note>
</document>
<document>
<note ns:data="foo">edcba</note>
</document>
<document>
<note data="foo">123</note>
</document>
<document>
<note ns:data="boo">abcde</note>
</document>
</docs>
EOL;

$xml = simplexml_load_string($str);

$xml->registerXPathNamespace('namespace', 'http://hoge/fuga/');
var_dump($xml->xpath('//note[@namespace:]'));print "<br>\n";

$res = $xml->xpath('//note[@namespace:data="foo"]');
var_dump($res);

結果は、

array(2) {

[0]=>

object(SimpleXMLElement)#2 (1) {

[0]=>

string(5) "abcde"

}

[1]=>

object(SimpleXMLElement)#3 (1) {

[0]=>

string(5) "edcba"

}

}

そうじゃなくて、どんな属性が使われているかなら、

一旦 file_get_contents などで読み込み、

名前空間の接頭辞(xmlns をキーにして探す)を preg_match() 等で見つけて、

その接頭辞のついている属性を preg_match_all で探して配列に入れる

という手順が考えられます。

http://jp.php.net/manual/ja/function.simplexml-element-registerX...

id:tezcello No.3

回答回数460ベストアンサー獲得回数69ここでベストアンサー

ポイント26pt

フローを示すだけではアレなんで...

$str = <<< EOL
<?xml version="1.0" encoding="UTF-8"?>
<docs xmlns:ns="http://hoge/fuga/">
<document>
<note ns:data="foo">abcde</note>
</document>
<document>
<note ns:data="hoo">edcba</note>
</document>
<document>
<note data="poo">123</note>
</document>
<document>
<note ns:data="boo">abcde</note>
</document>
</docs>
EOL;

$prefix = ''; $ns = '';

// 接頭辞や名前空間が既知なら上で定義すれば下3行は不要
if (preg_match('/xmlns:([-\w.]+)="(.+?)"/', $str, $tmp)){
  $prefix = $tmp[1]; $ns = $tmp[2];
}

preg_match_all('/\s'.$prefix.':([-\w.]+)="(.*?)"/', $str, $tmp);

var_dump($tmp[2]);

// simplexml での処理が必要ならこの先も
//$xml = simplexml_load_string($str);
//$xml->registerXPathNamespace('namespace', $ns);
//$res = $xml->xpath('//note[@namespace:data="foo"]');
//var_dump($res);
// 次の行が得られる
// array(1) { [0]=>  object(SimpleXMLElement)#2 (1) { [0]=>  string(5) "abcde" } }

array(3) { [0]=> string(3) "foo" [1]=> string(3) "hoo" [2]=> string(3) "boo" }

http://jp.php.net/manual/ja/function.preg-match-all.php

id:hiroshimo

回答ありがとうございます。非常にためになりました。少し質問のしかたがまずかったように思うので再度提示させていただきたいと思います。

<document>

<note data="foo">A</note>

<note data="bar">B</note>

</document>

うえのようなXMLがあったとして、AとかBを取り出そうとしたらこうですよね?

foreach ($xml as $document) {

echo $document->note, '
';

}

fooとかbarを取り出そうとしたら、こうですよね。

foreach ($xml as $document) {

echo $document->note[data], '
';

}

これをしたいのですが、dataにns:という接頭辞が付いているとうまくいきません。

foreach ($xml as $document) {

echo $document->note[ns:data], '
';

}

というようなことを解決したいのですが・・・。どうしたらいいのでしょう?

2008/02/13 14:40:31
  • id:hiroshimo
    回答制限をしていたためtezcelloさんからの回答が掲載できませんでしたので、ここの再掲させていただきます。
    ====
    回答数制限&コメントが付けられない なのでこちらか失礼します。

    $str = <<< EOL
    <?xml version="1.0" encoding="UTF-8"?>
    <docs xmlns:ns="http://hoge/fuga/">
    <document>
    <note ns:data="foo">abcde</note>
    </document>
    <document>
    <note ns:data="hoo">edcba</note>
    </document>
    <document>
    <note data="poo">123</note>
    </document>
    <document>
    <note ns:data="boo">ghijk</note>
    </document>
    </docs>
    EOL;

    $prefix = 'ns';

    $xml = simplexml_load_string($str);

    foreach ($xml as $x){
    print 'attribute = '.$x->note->attributes($prefix, 1)."\n";
    print 'children = '.$x->children()."\n";
    print "\n";
    }

    こんな感じで、ご希望のものに近付いたのではないかと思うのですが、いかがでしょうか?

    simplexml を熟知している訳ではないので、マニュアルを読み返してみて見つけました。
    これを知っていれば、回答として示したものは、もっとスッキリしたものだったのに...
    僕自身も大変勉強になりました。
    ====

    tezcelloさん、ありがとうございました!

    attributes属性にprefixを指定できるとは知りませんでした。すっきり解決しました。
    ただ、間借りしているサーバーだと SimpleXMLElement::attributes() expects at most 1 parameter, 2 given というエラーが出るんですよね。調べたらphpが5.0.4でした。5.2.5 だと問題なかったんですが。

    今回は大変勉強になりました。ありがとうございました。
  • id:tezcello
    いるか ありがとうございました。

    5.1.x -> 5.2.x の際に、is_prefix が追加になったという記事が見つかりました。
    という事は、接頭辞ではなく名前空間を指示すればよいのでは?
    $x->note->attributes('http://hoge/fuga/', 1)
    って感じで。

この質問への反応(ブックマークコメント)

トラックバック

「あの人に答えてほしい」「この質問はあの人が答えられそう」というときに、回答リクエストを送ってみてましょう。

これ以上回答リクエストを送信することはできません。制限について

回答リクエストを送信したユーザーはいません