PHP XML - 在特定位置插入XML节点

时间:2010-06-16 15:19:27

标签: php xml

我想在XML文件中的特定位置插入带子项的节点。我该怎么做?

例如。如果我有一个XML:

<myvalues>
 <image name="img01">
    <src>test</src>
 </image>

 <image name="img02">
    <src>test</src>
 </image>

 <image name="img03">
    <src>test</src>
 </image>
</myvalues>

我想插入:

<image name="img11">
  <src>test2</src>
</image>

介于<image name="img01">之间<image name="img02">。我该怎么做呢?我现在正在使用SimpleXML来读取XML。

感谢。

编辑:我尝试了以下代码。但是,新节点添加在XML结构外部的XML底部。

$xml = new DomDocument();


$xml->preserveWhitespace = false;
 $xml->load('myXMLFile.xml');

 $newNode = $xml->createElement('tryimage');

 $xpath = new DOMXpath($xml);
 $elements = $xpath->query('/myvalues/image[name="img01"]');

 $refNode = $elements->item(0);

 $xml->insertBefore($newNode, $refNode->nextSibling);


 header('Content-Type: text/plain');
 echo $xml->saveXML();

输出是这样的:

<xml....>
   <myvalues>
     <image name="01">
     </image>
     .
     .
     .
   </myvalues>
<tryimage />

2 个答案:

答案 0 :(得分:3)

嗯,我用SimpleXML看不出简单的方法(毕竟它应该很简单)。

一种方法是将myvalues节点移到DOMDocument,在那里添加节点,然后用dom节点替换它。鉴于$myvalues是SimpleXML中的<myvalues>节点:

$domMyValues = dom_import_simplexml($myvalues);
$newNode = $domMyValues->ownerDocument->createElement('mynewelement');
//Apply attributes and whatever to $newNode

//find the node that you want to insert it before (from the $domMyValues class
$nodes = $domMyValues->getElementsByTagName('image');
$refNode = null;
foreach ($nodes as $node) {
    if ($node->getAttribute('name') == 'img02') {
        $refNode = $node;
    }
}
$domMyValues->insertBefore($newNode, $refNode);

注意,没有必要转换回SimpleXML,因为对DOMElement的任何更改都将自动应用于SimpleXML版本...如果找不到$refNode,它将自动附加新的子项(因为它不存在,等等)......

编辑:添加XPath

用这个替换foreach块(如果我的查询正确,则在功能上等效):

$xpath = new DOMXpath($domMyValues->ownerDocument);
$elements = $xpath->query('//image[@name="img02"]');
$refNode = $elements->item(0);

由于DOMNodeList::item()对于不存在的偏移量返回null,我们甚至不需要检查其中是否有项目。

现在,您可能需要/想要将xpath查询调整为更多/更少特定。这是decent tutorial ...

修改2

我忘了xpath需要一个@字符来告诉它检查一个属性。

这是我的工作代码(因为我不知道你的确切架构):

$x = '<?xml version="1.0" ?>
<myvalues>
        <images>
                <image name="01">Foo</image>
                <image name="02">Bar</image>
        </images>
</myvalues>';

$dom = new DomDocument();
$dom->loadXML($x);
$xpath = new DOMXpath($dom);

$elements = $xpath->query('//images/image[@name="01"]');
$elements = $xpath->query('//image[@name="01"]');
$elements = $xpath->query('/myvalues/images/image[@name="01"]');

答案 1 :(得分:2)

ircmaxel's answer中所述,您可以使用DOM类/方法来执行您想要的操作。下面是一个简洁的(可能比真正想要使用的代码更少的代码)在另一个之后插入SimpleXMLElement的示例。

function insertAfter(SimpleXMLElement $new, SimpleXMLElement $target) {
    $target = dom_import_simplexml($target);
    $new    = $target->ownerDocument->importNode(dom_import_simplexml($new), true);
    if ($target->nextSibling) {
        $target->parentNode->insertBefore($new, $target->nextSibling);
    } else {
        $target->parentNode->appendChild($new);
    }
}

$sxe = new SimpleXMLElement($xml);
$img = $sxe->xpath('//image[@name="img01"]'); // xpath returns an array
if (!empty($img)) {
    $new = new SimpleXMLElement('<image name="img11" foo="bar"><src>test</src></image>');
    insertAfter($new, $img[0]);
}

foreach ($sxe as $image) {
    echo $image['name'] . PHP_EOL;
}
/*
    img01
    img11
    img02
    img03
*/