How to finding certain content with path and add one new Element? - php

HI I have a php script which finds certain Words in an XML file. I would like to add a new XML element if a certain word was found at the end of the file. But in my code it add one every time it finds one.
What I am doing wrong?
XML:
<products>
<product>
<title>TestProduct</title>
<Specifications>
<item name="Specifications1">Test</item>
<item name="Specifications2">Hello World</item>
</Specifications>
<body>
<item name="Color">Black</item>
</body>
</product>
</products>
PHP:
$dom = new DOMDocument;
$dom->load('Test.xml');
$xpath = new DOMXPath($dom);
foreach ($xpath->query("//*[contains(., 'Black')]") as $item) {
$element = $dom->createElement('ID', '123');
$item->appendChild($element);
}
echo $dom->saveXML();
should look like that:
<products>
<product>
<title>TestProduct</title>
<Specifications>
<item name="Specifications1">Test</item>
<item name="Specifications2">Hello World</item>
</Specifications>
<body>
<item name="Color">Black</item>
</body>
<ID>123</ID>
</product>
</products>

If I undertood correctly, you can your change xpath with
//product[contains(body/item, 'Black')]
Then the code will add new ID tag to the product, having item with the value 'Black'
demo

Related

How can I remove certain elements from XML using SimpleXML

I load the following XML data into SimpleXML like this:
<?php
$xmlString = <<<'XML'
<?xml version="1.0"?>
<response>
<item key="0">
<title>AH 2308</title>
<field_a>3.00</field_a>
<field_b>7.00</field_b>
<field_d1>35.00</field_d1>
<field_d2>40.00</field_d2>
<field_e></field_e>
<field_g2></field_g2>
<field_g>M 45x1,5</field_g>
<field_gewicht>0.13</field_gewicht>
<field_gtin>4055953012781</field_gtin>
<field_l>40.00</field_l>
<field_t></field_t>
<field_abdrueckmutter>KM 9</field_abdrueckmutter>
<field_sicherung>MB 7</field_sicherung>
<field_wellenmutter>KM 7</field_wellenmutter>
</item>
<item key="1">
<title></title>
<field_a></field_a>
<field_b></field_b>
<field_d1></field_d1>
<field_d2></field_d2>
<field_e></field_e>
<field_g2></field_g2>
<field_g></field_g>
<field_gewicht></field_gewicht>
<field_gtin></field_gtin>
<field_l></field_l>
<field_t></field_t>
<field_abdrueckmutter></field_abdrueckmutter>
<field_sicherung></field_sicherung>
<field_wellenmutter></field_wellenmutter>
</item>
</response>
XML;
$xml = simplexml_load_string($xml);
How can I achieve the following result:
<?xml version="1.0"?>
<response>
<item key="0">
<title>AH 2308</title>
<field_a>3.00</field_a>
<field_b>7.00</field_b>
<field_d1>35.00</field_d1>
<field_d2>40.00</field_d2>
<field_e></field_e>
<field_g2></field_g2>
<field_g>M 45x1,5</field_g>
<field_gewicht>0.13</field_gewicht>
<field_gtin>4055953012781</field_gtin>
<field_l>40.00</field_l>
<field_t></field_t>
<field_abdrueckmutter>KM 9</field_abdrueckmutter>
<field_sicherung>MB 7</field_sicherung>
<field_wellenmutter>KM 7</field_wellenmutter>
</item>
<item key="1"></item>
</response>
To delete all empty elements, I could use the following working code:
foreach ($xml->xpath('/child::*//*[not(*) and not(text()[normalize-space()])]') as $emptyElement) {
unset($emptyElement[0]);
}
But that's not exactly what I want.
Basically, when the <title> element is empty, I want to remove it with all its siblings and keep the parent <item> element.
What's important: I also want to keep empty element, if the <title> is not empty. See <item key="0"> for example. The elements <field_e>, <field_g2> and <field_t>will be left untouched.
Is there an easy xpath query which can achieve that? Hope anyone can help. Thanks in advance!
This xpath query is working:
foreach ($xml->xpath('//title[not(text()[normalize-space()])]/following-sibling::*') as $emptyElement) {
unset($emptyElement[0]);
}
It keeps the <title> element but I can live with that.
DOM is more flexible manipulating nodes:
$document = new DOMDocument();
$document->loadXML($xmlString);
$xpath = new DOMXpath($document);
$expression = '/response/item[not(title[normalize-space()])]';
foreach ($xpath->evaluate($expression) as $emptyItem) {
// replace children with an empty text node
$emptyItem->textContent = '';
}
echo $document->saveXML();

Remove one tag and all of it's child nodes of a xml using php

i'm trying to remove one item from a xml with all of it's child nodes but when i excecute following php only the child nodes will be removed.
following is my php
<?php
header('Content-Type: text/xml');
$doc = new DOMDocument('1.0');
$url = '../../data/auction.xml';
$itemNo ="0";
$xml=simplexml_load_file($url);
foreach($xml->xpath('/items/item[itemNumber="'.$itemNo.'"]')as $child)
{
unset($child[0]);
//$child->parentNode->removeChild($node);
}
print $xml->asXML();
?>
the original XML
<?xml version="1.0"?>
<items>
<item>
<itemNumber>0</itemNumber>
<itemName>item1</itemName>
<category>Phones</category>
</item>
<item>
<itemNumber>2</itemNumber>
<itemName>item3</itemName>
<category>laptops</category>
</item>
</items>
Actual output
<items>
<item>
</item>
<item>
<itemNumber>2</itemNumber>
<itemName>item3</itemName>
<category>laptops</category>
</item>
</items>
Desired output
<items>
<item>
<itemNumber>2</itemNumber>
<itemName>item3</itemName>
<category>laptops</category>
</item>
</items>
Please tell me what i'm doing wrong

Parse XML Parent node of matching attribute

I have an XML like the one below, I am trying to do an xpath query and parse it with simplexml. The XML is a CURL response and is stored in a $response variable. I need to look the Code attribute inside the <Item> and select the parent <Product> to parse it.
$response:
<Items>
<Product>
<Item Code="123">
</Item>
<Price>170
</Price>
</Product>
<Product>
<Item Code="456">
</Item>
<Price>150
</Price>
</Product>
</Items>
This is what I am doing:
$xml = simplexml_import_dom($response);
function loadNode($code){
global $xml;
$scode = $xml->xpath('//Item[contains(#Code,"' . $code . '")]/..');
echo $scode->Items->Product->Price;
}
loadNode("123");
This is the Notice I get:
Notice: Trying to get property of non-object
A couple of observations:
The xpath() method returns an array of SimpleXMLElement
objects, not a single SimpleXMLElement. (Yes, even though there can only be a single parent of an element, you still have to get it as the first member of the array ([0]).
$scode->Items->Product->Price should be changed to just
$scode->Price.
These modifications to your PHP code:
<?php
$response = <<<XML
<Items>
<Product>
<Item Code="123">
</Item>
<Price>170
</Price>
</Product>
<Product>
<Item Code="456">
</Item>
<Price>150
</Price>
</Product>
</Items>
XML;
$xml = simplexml_load_string($response);
function loadNode($code) {
global $xml;
$scode = $xml->xpath('//Item[contains(#Code,' . $code . ')]/..')[0];
echo $scode->Price;
}
loadNode("123");
?>
When run will yield this output:
170
as expected.

How to make child xml node with while loop using php

$xml = new DOMDocument();
$root=$xml->createElement("ROOT");
$xml->appendChild($root);
$data=$xml->createElement("DATA");
while($row=db_fetch_object($result))
{
$data=$xml->createElement("ITEM");
$item->setAttribute("COMPANY",$row->field_windmill_fabrikant_value);
$item->setAttribute("HEIGHT",$row->field_windmill_ashoogte_value);
$item->setAttribute("POWER",$row->field_windmill_vermogen_value);
$item->setAttribute("LOCATION",$row->field_windmill_provincie_value);
$item->setAttribute("START_YEAR",$row->field_windmill_startjaar_value);
$data->appendChild($item);
}
$root->appendChild($data);
echo $xml->saveXML();
Here I want to append ITEM as a child node to data but ITEM is getting appended to item and not to data. I'm using PHP.
Can anyone help in it.
Thanks.
Just replace
$data=$xml->createElement("ITEM");
with
$item=$xml->createElement("ITEM");
result of this will be
<?xml version="1.0"?>
<ROOT>
<DATA>
<ITEM COMPANY="COMPANY0" HEIGHT="HEIGHT0" POWER="POWER0" LOCATION="LOCATION0" START_YEAR="START_YEAR0"/>
<ITEM COMPANY="COMPANY1" HEIGHT="HEIGHT1" POWER="POWER1" LOCATION="LOCATION1" START_YEAR="START_YEAR1"/>
<ITEM COMPANY="COMPANY2" HEIGHT="HEIGHT2" POWER="POWER2" LOCATION="LOCATION2" START_YEAR="START_YEAR2"/>
</DATA>
</ROOT>

need help.. php soap

I have a xml document, i need to get name attribute's value with helping php. the xml file looks like this:
<?xml version="1.0" encoding="utf-8"?>
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
<S:Body>
<ns2:GetGoodsTreeResponse xmlns:ns2="http://b2b.alta.com.ge" xmlns:ns3="http://192.168.0.10/b2b">
<ns3:GoodsTree level="0">
<item id="010000000017337" level="0" name="COMPUTERS" is_open="N">
<item id="015000000030431" level="1" name="ALTA" is_open="Y">
<item id="015000000030443" level="2" name="Zakaznoe Izdelie" is_open="N"/>
<item id="015002000031034" level="2" name="ATOM" is_open="N"/>
<item id="015005000030453" level="2" name="Celeron" is_open="N"/>
<item id="015010000030432" level="2" name="Dual Core" is_open="N"/>
<item id="015150000030778" level="2" name="i3" is_open="N"/>
<item id="015220000030775" level="2" name="i5" is_open="N"/>
<item id="015300000031827" level="2" name="i7" is_open="N"/>
</item>
<item id="010001005030300" level="1" name="Apple" is_open="N"/>
<item id="010001001033496" level="1" name="Asus" is_open="N"/>
<item id="010001001015793" level="1" name="Fujitsu" is_open="N"/>
<item id="010001002015166" level="1" name="HP Compaq" is_open="N"/>
</item>
</ns3:GoodsTree>
</ns2:GetGoodsTreeResponse>
</S:Body>
</S:Envelope>
please help me i dont know what to do.. sorry for my english.
You can use DOMDocument to parse that XML and get all items using DOMXpath, then loop in all items and get the attributes based on position (id = 0, name = 2), then create an new array that will hold all you item id's with their names:
$dom = new DOMDocument;
$dom->loadXML($xml);
$xpath = new DOMXPath($dom);
$xpath->registerNamespace('S', 'http://schemas.xmlsoap.org/soap/envelope/');
$items = array();
$el = $xpath->query('//item');
foreach($el as $item){
$attributes = $item->attributes;
$items[$attributes->item(0)->value] = $attributes->item(2)->value;
}
var_dump($items); // $items will be an array with item id and it's value will be item name
Codepad Example

Categories