Учитывая приведенный ниже пример XML, который основан на цитируемом в вопросе, но немного расширен и исправил неправильно сформированный XML, как показано выше, вы можете легко получить желаемую структуру с осторожным использованием DOMXPath
и insertBefore
-с небольшим поворотом на последнем, чтобы фактически выполнить insertAfter
<code>$xml='<?xml version="1.0" encoding="UTF-8"?>
<Root>
<Products>
<Product>
<productname> pr_name 1</productname>
<price> pr_price 1</price>
<sku> pr_sku 1</sku>
<Image> image_url 1.1</Image>
<Image> image_url 1.2</Image>
</Product>
<Product>
<productname> pr_name 2</productname>
<price> pr_price 2</price>
<sku> pr_sku 2</sku>
<Image> image_url 2</Image>
</Product>
<Product>
<productname> pr_name 3</productname>
<price> pr_price 3</price>
<sku> pr_sku 3</sku>
<Image> image_url 3.1</Image>
<Image> image_url 3.2</Image>
<Image> image_url 3.3</Image>
</Product>
<Product>
<productname> pr_name 4</productname>
<price> pr_price 4</price>
<sku> pr_sku 4</sku>
</Product>
</Products>
</Root>';
$dom=new DOMDocument('1.0','utf-8');
$dom->formatOutput=true;
$dom->validateOnParse=false;
$dom->recover=true;
$dom->strictErrorChecking=false;
$dom->preserveWhiteSpace=false;
$dom->loadXML( $xml );
$errors = libxml_get_errors();
libxml_clear_errors();
$xp=new DOMXPath( $dom );
$col=$xp->query( '//Products/Product' );
if( $col->length > 0 ){
foreach( $col as $node ){
/* Get the `productname` and create a new element before with same value */
$productname=$xp->query( 'productname', $node )->item(0);
$newproductname=$dom->createElement( 'newproductname', $productname->textContent );
$node->insertBefore( $newproductname, $productname );
/* Find all the Image tags within parent */
$ref=$xp->query( 'Image', $node );
/* determine reference node to use for `insertBefore` */
if( $ref && $ref->length > 0 )$refNode=$ref->item(0);
else $refNode=$node->lastChild;
/* create a new `Images` node */
$oImages=$dom->createElement('Images');
$node->insertBefore( $oImages, $refNode );
/* using previously discovered `Image` nodes, add to the new `Images` element */
foreach( $ref as $img )$oImages->appendChild( $img );
}
}
/* for demo display */
printf('<pre>%s
', print_r (htmlentities ($ dom-> saveXML ()), true));/ * Для реального вывода * / #header ('Content-Type: application / xml');#exit ($ dom-> saveXML ());
Вывод отладочной печати (printf
выше) выглядит следующим образом и, как я полагаю, следует желаемому формату вывода - кроме нового, не упомянутого тега newsku
, который вы показываете выше:
<?xml version="1.0" encoding="UTF-8"?>
<Root>
<Products>
<Product>
<newproductname> pr_name 1</newproductname>
<productname> pr_name 1</productname>
<price> pr_price 1</price>
<sku> pr_sku 1</sku>
<Images>
<Image> image_url 1.1</Image>
<Image> image_url 1.2</Image>
</Images>
</Product>
<Product>
<newproductname> pr_name 2</newproductname>
<productname> pr_name 2</productname>
<price> pr_price 2</price>
<sku> pr_sku 2</sku>
<Images>
<Image> image_url 2</Image>
</Images>
</Product>
<Product>
<newproductname> pr_name 3</newproductname>
<productname> pr_name 3</productname>
<price> pr_price 3</price>
<sku> pr_sku 3</sku>
<Images>
<Image> image_url 3.1</Image>
<Image> image_url 3.2</Image>
<Image> image_url 3.3</Image>
</Images>
</Product>
<Product>
<newproductname> pr_name 4</newproductname>
<productname> pr_name 4</productname>
<price> pr_price 4</price>
<Images/>
<sku> pr_sku 4</sku>
</Product>
</Products>
</Root>