2017-05-16 1 views
0

私は、階層の種類を持って記事の情報を含むXML文書を、持っている:解析XML文書再帰

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

<page> 
<elements> 

<element> 
<type>article</type> 
<id>1</id> 
<parentContainerID>page</parentContainerID> 
<parentContainerType>page</parentContainerType> 
</element> 

<element> 
<type>article</type> 
<id>2</id> 
<parentContainerID>1</parentContainerID> 
<parentContainerType>article</parentContainerType> 
</element> 

<element> 
<type>photo</type> 
<id>3</id> 
<parentContainerID>2</parentContainerID> 
<parentContainerType>article</parentContainerType> 
</element> 

<... more elements ..> 

</elements> 
</page> 

要素はノードparentContainerIDとノードparentContainerTypeを持っています。 parentContainerType == pageの場合、これはマスター要素です。 parentContainerIDは要素のマスターが何であるかを示します。だから、それは次のようになります。1 <から2 <から3

今、私はこのようになりますこのようなものの新しいページ(HTML)を構築する必要があります:ID 1の コンテンツ、ID 2のコンテンツ、IDの内容を3(IDは進行中ではない)。

これは再帰関数を使って行うことができると思います。しかし、私はこれをどのように管理するか分かりません。

+1

_ "このような内容の新しいページ(html)を作成する必要があります:ID1のコンテンツ、ID2のコンテンツ、ID3のコンテンツ" _ - ちょうど順次 - またはネストされたXMLで定義された親子関係ネストされていない場合、なぜここで再帰を使用しますか?XMLの要素はネストされていませんが、それらはすべて同じレベルにあります。おそらく、まず配列に配列を読み込んだ後、それに応じてソートしてから、必要な出力を生成するためにループします。 – CBroe

+0

CBroe、親子関係による。 – DaFunkyAlex

答えて

1

ここでは、XMLにネスト/再帰はありません。 <element/>ノードは兄弟です。親子関係を構築するには、XMLをループして2つの配列を作成することをお勧めします。 1つは関係のためのものであり、もう1つは要素の参照です。

$xml = file_get_contents('php://stdin'); 

$document = new DOMDocument(); 
$document->loadXml($xml); 
$xpath = new DOMXpath($document); 

$relations = []; 
$elements = []; 
foreach ($xpath->evaluate('//element') as $element) { 
    $id = (int)$xpath->evaluate('string(id)', $element); 
    $parentId = (int)$xpath->evaluate('string(parentContainerID)', $element); 
    $relations[$parentId][] = $id; 
    $elements[$id] = $element; 
} 

var_dump($relations); 

出力:関係配列は、現在どの親の子IDが含まれてい

array(3) { 
    [0]=> 
    array(1) { 
    [0]=> 
    int(1) 
    } 
    [1]=> 
    array(1) { 
    [0]=> 
    int(2) 
    } 
    [2]=> 
    array(1) { 
    [0]=> 
    int(3) 
    } 
} 

、親のない要素はインデックス0にあるこれは、あなたがツリーとして再帰関数へのアクセスに要素を使用することができます。

function traverse(
    int $parentId, callable $callback, array $elements, array $relations, $level = -1 
) { 
    if ($elements[$parentId]) { 
    $callback($elements[$parentId], $parentId, $level); 
    } 
    if (isset($relations[$parentId]) && is_array($relations[$parentId])) { 
    foreach ($relations[$parentId] as $childId) { 
     traverse($childId, $callback, $elements, $relations, ++$level); 
    } 
    } 
} 

これは、各ノードのコールバックを実行します。これの適切な実装はRecursiveIteratorですが、この例では関数が必要です。

traverse(
    0, 
    function(DOMNode $element, int $id, int $level) use ($xpath) { 
    echo str_repeat(' ', $level); 
    echo $id, ": ", $xpath->evaluate('string(type)', $element), "\n"; 
    }, 
    $elements, 
    $relations 
); 

出力:$xpathオブジェクトは、コールバックにコンテキストとして提供されていることを

1: article 
2: article 
    3: photo 

注意してください。 $elements配列に元のノードが含まれているため、Xpath式を使用して、現在の要素ノードに関連するDOMから詳細なデータを取得できます。