4

次の構造の XML ドキュメントがあります。

<posts>
<user id="1222334">
  <post>
    <message>hello</message>
    <client>client</client>
    <time>time</time>
  </post>
  <post>
    <message>hello client how can I help?</message>
    <client>operator</client>
    <time>time</time>
  </post>
</user>
<user id="2333343">
  <post>
    <message>good morning</message>
    <client>client</client>
    <time>time</time>
  </post>
  <post>
    <message>good morning how can I help?</message>
    <client>operator</client>
    <time>time</time>
  </post>
</user>
</posts>

パーサーを作成してドキュメント全体を印刷することはできますが、特定の属性 (id) を持つ (ユーザー) ノードと子のみを印刷したいという問題があります。

私のPHPコードは次のとおりです。

if( !empty($_GET['id']) ){
    $id = $_GET['id'];
    $parser=xml_parser_create();
    function start($parser,$element_name,$element_attrs)
      {
    switch($element_name)
        {
        case "USER": echo "-- User --<br>";
        break;
        case "CLIENT": echo "Name: ";
        break;
        case "MESSAGE": echo "Message: ";
        break;
        case "TIME": echo "Time: ";
        break;
        case "POST": echo "--Post<br> ";
        }
  }

function stop($parser,$element_name){  echo "<br>";  }
function char($parser,$data){ echo $data; }
xml_set_element_handler($parser,"start","stop");
xml_set_character_data_handler($parser,"char");

$file = "test.xml";
$fp = fopen($file, "r");
while ($data=fread($fp, filesize($file)))
  {
  xml_parse($parser,$data,feof($fp)) or 
  die (sprintf("XML Error: %s at line %d", 
  xml_error_string(xml_get_error_code($parser)),
  xml_get_current_line_number($parser)));
  }
xml_parser_free($parser);
}

関数でこれを使用start()すると、正しいノードを選択できますが、読み取りプロセスには影響しません。

    if(($element_name == "USER") && $element_attrs["ID"] && ($element_attrs["ID"] == "$id"))

任意の助けをいただければ幸いです

更新: XMLReader は動作しますが、if ステートメントを使用すると動作しなくなります:

foreach ($filteredUsers as $user) {
echo "<table border='1'>";
foreach ($user->getChildElements('post') as $index => $post) {

    if( $post->getChildElements('client') == "operator" ){
    printf("<tr><td class='blue'>%s</td><td class='grey'>%s</td></tr>", $post->getChildElements('message'), $post->getChildElements('time'));
    }else{
    printf("<tr><td class='green'>%s</td><td class='grey'>%s</td></tr>", $post->getChildElements('message'), $post->getChildElements('time'));

    }
}
echo "</table>";
}
4

2 に答える 2

8

以前のコメントで提案されているように、代わりにXMLReaderDocsを使用できます。

XMLReader 拡張機能は、XML プル パーサーです。リーダーは、ドキュメント ストリームを進み、途中の各ノードで停止するカーソルとして機能します。

XMLReaderファイルを開くことができるクラス (同名: ) です。デフォルトではnext()、次のノードに移動するために使用します。次に、現在の位置が要素にあるかどうかを確認し、その要素に探している名前があるかどうかを確認してから、要素XMLReader::readOuterXml()Docsの外側の XML を読み取るなどして、それを処理できます。

Expat パーサーのコールバックと比べると、これは少し面倒です。柔軟性を高めるために、XMLReader私は通常、オブジェクトを操作して必要なステップを提供できるイテレータをXMLReader自分で作成します。

を使用して具体的な要素を直接反復処理できforeachます。以下にその例を示します。

require('xmlreader-iterators.php'); // https://gist.github.com/hakre/5147685

$xmlFile = '../data/posts.xml';

$ids = array(3, 8);

$reader = new XMLReader();
$reader->open($xmlFile);

/* @var $users XMLReaderNode[] - iterate over all <user> elements */
$users = new XMLElementIterator($reader, 'user');

/* @var $filteredUsers XMLReaderNode[] - iterate over elements with id="3" or id="8" */
$filteredUsers = new XMLAttributeFilter($users, 'id', $ids);

foreach ($filteredUsers as $user) {
    printf("---------------\nUser with ID %d:\n", $user->getAttribute('id'));
    echo $user->readOuterXml(), "\n";
}

あなたの質問のようないくつかの投稿を含むXMLファイルを作成しました。id属性で1から上に番号が付けられています。

$xmlFile = '../data/posts.xml';

次に、関心のあるユーザーの 2 つの ID 値を含む配列を作成しました。

$ids = array(3, 8);

後でフィルター条件で使用されます。次にXMLReaderが作成され、XML ファイルが開かれます。

$reader = new XMLReader();
$reader->open($xmlFile);

<user>次のステップでは、そのリーダーのすべての要素に対して反復子を作成します。

$users = new XMLElementIterator($reader, 'user');

次に、id以前に配列に格納された属性値に対してフィルター処理されます。

$filteredUsers = new XMLAttributeFilter($users, 'id', $ids);

foreachすべての条件が定式化されたので、残りは現在反復中です。

foreach ($filteredUsers as $user) {
    printf("---------------\nUser with ID %d:\n", $user->getAttribute('id'));
    echo $user->readOuterXml(), "\n";
}

これは、ID が 3 と 8 のユーザーの XML を返します。

---------------
User with ID 3:
<user id="3">
        <post>
            <message>message</message>
            <client>client</client>
            <time>time</time>
        </post>
    </user>
---------------
User with ID 8:
<user id="8">
        <post>
            <message>message 8.1</message>
            <client>client</client>
            <time>time</time>
        </post>
        <post>
            <message>message 8.2</message>
            <client>client</client>
            <time>time</time>
        </post>
        <post>
            <message>message 8.3</message>
            <client>client</client>
            <time>time</time>
        </post>
    </user>

XMLReader イテレータXMLReaderNode一部である which は要素内の値を簡単に読み取りたい場合に備えてSimpleXMLElementDocsも提供します。<user>

次の例は、<post>要素内の<user>要素の数を取得する方法を示しています。

foreach ($filteredUsers as $user) {
    printf("---------------\nUser with ID %d:\n", $user->getAttribute('id'));
    echo $user->readOuterXml(), "\n";
    echo "Number of posts: ", $user->asSimpleXML()->post->count(), "\n";
}

これはNumber of posts: 1、ユーザー ID 3 とNumber of posts: 3ユーザー ID 8 に対して表示されます。

ただし、その外側の XML が大きい場合は、それを行う必要はなく、その要素内で反復処理を続行する必要があります。

// rewind
$reader->open($xmlFile);

foreach ($filteredUsers as $user) {
    printf("---------------\nUser with ID %d:\n", $user->getAttribute('id'));
    foreach ($user->getChildElements('post') as $index => $post) {
        printf(" * #%d: %s\n", ++$index, $post->getChildElements('message'));
    }
    echo "Number of posts: ", $index, "\n";
}

次の出力が生成されます。

---------------
User with ID 3:
 * #1: message 3
Number of posts: 1
---------------
User with ID 8:
 * #1: message 8.1
 * #2: message 8.2
 * #3: message 8.3
Number of posts: 3

この例は、ネストされた子の大きさに応じて、使用可能な反復子を使用してさらに走査したり、XML のサブセットのgetChildElements()ような一般的な XML パーサーを使用したりできることを示しています。SimpleXMLDOMDocument

于 2013-03-15T23:09:23.550 に答える
0

PHP SimpleDomHTML を使用できます (PHP5+ で作成された HTML DOM パーサーを使用すると、HTML を非常に簡単な方法で操作できます!) jQuery を使用する場合と同じようにデータを照会できます。HTML をサポートしているため、XML ドキュメントも確実にサポートします。

ドキュメントはhttp://simplehtmldom.sourceforge.net/からダウンロードして表示できます。

于 2013-03-15T02:58:35.863 に答える