PHP - DOM - XML ​​- Узлы с похожими атрибутами - PullRequest
3 голосов
/ 23 февраля 2012

Я должен манипулировать файлом XML с помощью DOM

Это моя ситуация:

<mainnode>
<node1  name="aaa">
           <subnode   name="123456" />
    </node1>

    <node1  name="bbb">
           <subnode   name="28472" />
    </node1>

    <node1  name="aaa">
           <subnode   name="92328" />
    </node1>

    <node1  name="ccc">
           <subnode   name="53554" />
    </node1>

    <node1  name="ccc">
           <subnode   name="01928" />
    </node1>

    <node1  name="aaa">
           <subnode   name="39576" />
    </node1>

    <node1  name="ddd">
           <subnode   name="66666" />
    </node1>
</mainnode>

И я хочу сгруппировать все мои узлы, считывающие атрибут "name" в <node1>чтобы получить что-то подобное для каждого «имени», равного другому:

<mainnode>    
<node1 name="aaa">
          <subnode   name="123456" />
          <subnode   name="92328" />
          <subnode   name="39576" />
    </node1>


    <node1  name="bbb">
          <subnode   name="28472" />
    </node1>

    <node1  name="ccc">
          <subnode   name="53554" />
          <subnode   name="01928" />
     </node1>

    <node1  name="ddd">
          <subnode   name="66666" />
    </node1>
</mainnode>

Что такое код php для такой манипуляции с dom?это возможно?

Ответы [ 3 ]

1 голос
/ 23 февраля 2012

Вы можете сделать это следующим образом (пожалуйста, убедитесь, что ваш XML нормализован раньше):

// load the xml and prepare the dom
$dom = new DOMDocument('1.0', 'UTF-8');

// do not display parsing errors to the user
libxml_use_internal_errors(true)

// load xml
$dom->loadXML($string);

// optionally handle parsing errors provided in libxml_get_errors()

// store the node names
$nodeNames = array();

// get all nodes
$nodes = $dom->getElementsByTagName('node1');


foreach ($nodes as $node)
{
    /* @var $node DOMElement */
    $nodeName = $node->getAttribute("name");

    if (isset($nodeNames[$nodeName]))
    {
        /* @var $previousNode DOMElement */
        $previousNode = $nodeNames[$nodeName];

        if ($node->hasChildNodes())
        {
            foreach ($node->childNodes as $childNode)
            {
                $previousNode->appendChild($childNode);
            }
        }

        $node->parentNode->removeChild($node);
    }
    else
    {
        $nodeNames[$nodeName] = $node;
    }
}
1 голос
/ 23 февраля 2012

Вы можете использовать расширение PHP XQuery, чтобы сделать это:

let $data := (: your xml :)
return
    element mainnode {
        for $nodes in $data/node1
        let $name := string($nodes/@name) 
        group by $name 
        return
         element {$name} {
             attribute name {$name},
            for $node in $nodes
            return $node/subnode 
        }
    }

Вы можете попробовать пример вживую по адресу http://www.zorba -xquery.com / html / demo # TuRqsG1GZewGQD3f0QhmsIpVmTc = Инструкции по установке расширения XQuery на PHP доступны по адресу http://www.zorba -xquery.com / html / entry / 2011/12/27 / PHP_Meets_XQuery

0 голосов
/ 23 февраля 2012

Предполагается, что $xml содержит вашу строку XML ( demo ):

$dom = new DOMDocument;
$dom->preserveWhiteSpace = false;
$dom->loadXML($xml);
$xpath = new DOMXPath($dom);
// iterate all the subnodes
foreach ($xpath->query('/nodes/node1/subnode') as $subnode) {
    // get the subnodes parent node's name attribute
    $name = $subnode->parentNode->getAttribute('name');
    // fetch the first node element with that name attribute
    $node = $xpath->query("/nodes/node1[@name='$name']")->item(0);
    // move the subnode there
    $node->appendChild($subnode);
}
// iterate over all node1 elements that are now empty
foreach($xpath->query('/nodes/node1[not(*)]') as $node) {
    // remove them
    $node->parentNode->removeChild($node);
}
// print new dom tree
$dom->formatOutput = true;
echo $dom->saveXML();

Обратите внимание, что я принимаю корневой узел <nodes>.

...