PHP XML inserting element after (or before) another element - php

I have a previously generated XML like this:
<newsletter>
<header>
</magazine>
</image>
<strap/>
</header>
<intro>
<date/>
<text/>
</edimg>
</intro>
<shop>
<heading/>
<article/>
<title/>
<img/>
<link/>
<excerpt/>
</shop>
<sidebar>
<cover/>
<cover_link/>
<text/>
<advert>
<link/>
<image/>
</advert>
</sidebar>
</newsletter>
I need to be able to insert an element in between the <intro> and the <shop> elements
this:
$section = $dom->documentElement->appendChild($dom->createElement('section'));
will just create the element within <newsletter> .
I assumed this would be fairly simple , but cannot seem to find a solution .
Thanks.

You might try this; I didn't test it, but the solution comes from using insertBefore instead of appendChild.
$shop = $dom->getElementsByTagName("shop")->item(0);
$section = $dom->documentElement->insertBefore($dom->createElement('section'),$shop);

Fetch the <shop> node and use
DOMNode::insertBefore — Adds a new child before a reference node
instead of appending to the documentElement.
You can do that from the DOMDocument as well when passing in the shop node as second argument. Personally, I find it easier to just do that from the shop node because you have to fetch it anyway:
$shopNode->insertBefore($newNode);

Try
$section = $dom->documentElement->insertBefore(
$dom->createElement('section'),
$shop)
);
where $shop points to the <shop> element.

Related

Get all children from certain xml child element using SimpleXMLElement and xpath

I have xml like:
<root xmlns="urn:test:apis:baseComponents">
<books>
<book>
<name>50 shades of grey</name>
</book>
</books>
<disks>
<disk>
<name>Britney Spears</name>
</disk>
</disks>
</root>
And such php code:
$xml = new SimpleXMLElement($xml);
$books = $xml->books;
$disks = $xml->disks;
$disks->registerXPathNamespace('x', 'urn:test:apis:baseComponents');
$books->registerXPathNamespace('x', 'urn:test:apis:baseComponents');
$b_names = $books->xpath('//x:name');
b_names contains array with 2 values instead of 1. First holds books->book->name, second holds disks->disk->name.
Can you please explain what am I doing wrong and how could I find children of only one element?
The reason that I am using xpath instead of taking manually values using SimpleXMLElement, is that I don't know what value, which I want to search in advance.
Use $books->xpath('.//x:name') to search descendants of your $books variable and not descendants of the root node/document node (which the path //x:name does).

How to Insert new XML element at the top of other nodes? [duplicate]

I have a previously generated XML like this:
<newsletter>
<header>
</magazine>
</image>
<strap/>
</header>
<intro>
<date/>
<text/>
</edimg>
</intro>
<shop>
<heading/>
<article/>
<title/>
<img/>
<link/>
<excerpt/>
</shop>
<sidebar>
<cover/>
<cover_link/>
<text/>
<advert>
<link/>
<image/>
</advert>
</sidebar>
</newsletter>
I need to be able to insert an element in between the <intro> and the <shop> elements
this:
$section = $dom->documentElement->appendChild($dom->createElement('section'));
will just create the element within <newsletter> .
I assumed this would be fairly simple , but cannot seem to find a solution .
Thanks.
You might try this; I didn't test it, but the solution comes from using insertBefore instead of appendChild.
$shop = $dom->getElementsByTagName("shop")->item(0);
$section = $dom->documentElement->insertBefore($dom->createElement('section'),$shop);
Fetch the <shop> node and use
DOMNode::insertBefore — Adds a new child before a reference node
instead of appending to the documentElement.
You can do that from the DOMDocument as well when passing in the shop node as second argument. Personally, I find it easier to just do that from the shop node because you have to fetch it anyway:
$shopNode->insertBefore($newNode);
Try
$section = $dom->documentElement->insertBefore(
$dom->createElement('section'),
$shop)
);
where $shop points to the <shop> element.

Show all items that Match in XML using PHP

This is my XML file named: full.xml
I need your help. I need a PHP script that open "full.xml"
and only display all values of the nodes that have .email
Example of the Output I want:
sales#company1.com
sales#company2.com
sales#company3.com
Thanks! I will thank you so much!
EDIT
$Connect = simplexml_load_file("full.xml");
return $Connect->table[0]->*.email;
The design of your XML is not very smart. With this xpath expression, you select all nodes with .email at the end of their name:
$xml = simplexml_load_string($x); // assume XML in $x
$results = $xml->xpath("//*[substring(name(),string-length(name())-" . (strlen('.email') - 1) . ") = '.email']");
--> result is an array with the selected nodes.
BTW: if you have any chance of CHANGING the structure of the XML, AVOID combining information within node names like <company1.email>, but do it like this:
...
<companies>
<company id="1">
<email>info#company1.com</email>
<tel>+498988123456</tel>
<name>somename</name>
</company>
<company id="2">
<email>info#company2.com</email>
<tel>+498988123457</tel>
<name>someothername</name>
</company>
</companies>
....
It will be much easier to read and parse.

How to insert one item before the first item currently without xpath in Domdocument using PHP [duplicate]

I have a previously generated XML like this:
<newsletter>
<header>
</magazine>
</image>
<strap/>
</header>
<intro>
<date/>
<text/>
</edimg>
</intro>
<shop>
<heading/>
<article/>
<title/>
<img/>
<link/>
<excerpt/>
</shop>
<sidebar>
<cover/>
<cover_link/>
<text/>
<advert>
<link/>
<image/>
</advert>
</sidebar>
</newsletter>
I need to be able to insert an element in between the <intro> and the <shop> elements
this:
$section = $dom->documentElement->appendChild($dom->createElement('section'));
will just create the element within <newsletter> .
I assumed this would be fairly simple , but cannot seem to find a solution .
Thanks.
You might try this; I didn't test it, but the solution comes from using insertBefore instead of appendChild.
$shop = $dom->getElementsByTagName("shop")->item(0);
$section = $dom->documentElement->insertBefore($dom->createElement('section'),$shop);
Fetch the <shop> node and use
DOMNode::insertBefore — Adds a new child before a reference node
instead of appending to the documentElement.
You can do that from the DOMDocument as well when passing in the shop node as second argument. Personally, I find it easier to just do that from the shop node because you have to fetch it anyway:
$shopNode->insertBefore($newNode);
Try
$section = $dom->documentElement->insertBefore(
$dom->createElement('section'),
$shop)
);
where $shop points to the <shop> element.

SimpleXML add element before

I'm using SimpleXML to generate xml based invoice.
The structure has to be like this (heavily simplified):
<invoice>
<total>
<price>100</price>
</total>
<items>
<item>...</item>
</items>
</invoice>
But if first loop my items and add totals together, and then insert <total>:
<invoice>
<items>...</items>
<total>...</total>
</invoice>
But CUSTOM XSD says it invalid. This probably will not cause an error in applications, but I'd like it to be valid.
So can I insert <total> tag before <items> tag?
Note: <items> tag is not the first element in <invoice>.
Jquery equivalent of the function in need is .insertBefore()
Cheers!
You can do something like this:
$domelement = dom_import_simplexml($items);
$new = $dom->insertBefore(
$dom->ownerDocument->createElement("total"),
$dom->firstChild
);
$newsxml = simplexml_import_dom($new);
then add the items into total node.

Categories