I have the following XML all contained in one cell in a MSSQL DB:
<receipt reference="INT000003" major="2" minor="14.804" beta="">
<dates id="Booking Dates">
<item id="Date of Booking">23 May 2013 - 17:09</item>
</dates>
<advertisement id="advertisement details">
<item id="Booked by">Mr System Administrator</item>
<item id="Brand or Product">Testing</item>
<item id="Priority">500</item>
</advertisement>
</receipt>
I want to get the value <item id="Brand or Product">Testing</item> out of that cell (specifically "Testing" though) to use in a PHP based webpage. Does anyone know of any PHP to read this type of XML and search for values?
Thanks.
You can use DOMXPath::query for it in PHP. First select the entire XML from the table as you normally would and then get the correct elements.
<?php
$xml = <<<END
<receipt reference="INT000003" major="2" minor="14.804" beta="">
<dates id="Booking Dates">
<item id="Date of Booking">23 May 2013 - 17:09</item>
</dates>
<advertisement id="advertisement details">
<item id="Booked by">Mr System Administrator</item>
<item id="Brand or Product">Testing</item>
<item id="Priority">500</item>
</advertisement>
</receipt>
END; //you would load it from the table
$dom = new DOMDocument;
$dom->loadXML($xml);
$xpath = new DOMXPath($dom);
$query = "//advertisement/item";
$items = $xpath->query($query);
foreach ($items as $item) {
echo $item->nodeValue;
}
?>
This will output
Mr System Administrator
Testing
500
And if you would need the value of a specific ID you can use
<?php
$dom = new DOMDocument;
$dom->loadXML($xml);
$xpath = new DOMXPath($dom);
$query = "//advertisement/item[#id='Brand or Product']";
$items = $xpath->query($query);
foreach ($items as $item) {
echo $item->nodeValue;
}
Output:
Testing
This can also done in SQL as below :
declare #xml xml =
'<receipt reference="INT000003" major="2" minor="14.804" beta="">
<dates id="Booking Dates">
<item id="Date of Booking">23 May 2013 - 17:09</item>
</dates>
<advertisement id="advertisement details">
<item id="Booked by">Mr System Administrator</item>
<item id="Brand or Product">Testing</item>
<item id="Priority">500</item>
</advertisement>
</receipt>'
select #xml.value
('(/receipt/advertisement/item[#id="Brand or Product"])[1]', 'nvarchar(100)')
Also, you can directly fetch the value from table as below :
select cast(YOUR_COLUMN_NAME as XML).value('(/receipt/advertisement/item[#id="Brand or Product"])[1]', 'nvarchar(100)')
as s from YOUR_TABLE_NAME
Related
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();
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
I (conceptually) understand which steps i have to take, but i can't translate it to a working code.
I have a XML feed with a structure like this:
<item id="1">
<properties>
<property name="region">
<value>Cote d'azur</value>
</property>
</properties>
</item>
<item id="2">
<properties>
<property name="region">
<value>Côte d'Azur</value>
</property>
</properties>
</item>
What i need is the feed to use consequent names, so i have to loop through each property with the name attribute and replace the value, but how?
So far i'm here, but this doesn't work
$xml_src = 'feed.xml';
$document = new DOMDocument();
$document->load($xml_src);
$xpath = new DOMXpath($document);
$regions = $xpath->evaluate('//property[#name = "region"]');
foreach($regions as $region){
$newregion = $document->createElement('value', str_replace("Cote d'azur","Côte d'Azur",$region->nodeValue));
$region->parentNode->replaceChild($newregion, $region);
}
echo $document->saveXml();
I get this error:
Warning: DOMDocument::createElement(): unterminated entity reference Ylläs in .. on line 17
Line 17:
$newregion = $document->createElement('value', str_replace("Cote d'azur","Côte d'Azur",$region->nodeValue));
To make it even more complicated, i sometimes have three value elements in each property with the name city. In that case i need to select the third element.
I hope anybody can help me out
The error message is from a bug in PHP. Do not use the second argument for DOMDocument::createElement(). Create and append a text node to make sure that special characters are escaped into entities.
https://stackoverflow.com/a/27225157/2265374
Anything in a DOM is a node. Not only the element, but attribute and texts, too. You can work on the text nodes inside the value elements directly:
$document = new DOMDocument();
$document->loadXml($xml);
$xpath = new DOMXpath($document);
foreach ($xpath->evaluate('//property[#name = "region"]/value/text()') as $text) {
$text->data = str_replace("Cote d'azur","Côte d'Azur", $text->data);
}
echo $document->saveXml();
Simple:
$regions = $xpath->query('//property[#name = "region"]/value');
foreach($regions as $region){
$region->nodeValue = str_replace("Cote d'azur","Côte d'Azur",$region->nodeValue);
}
echo $document->saveXml();
i have a XML document that looks like this:
<body>
<item id="9982a">
<value>ab</value>
</item>
<item id="9982b">
<value>abc</value>
</item>
etc...
</body>
Now, i need to get the value for a key, the document is very very big, is there any way to go directly to the key when i know the id? Rather then loop it?
Something like:
$xml = simplexml_load_string(file_get_contents('http://somesite.com/new.xml'));
$body = $xml->body;
$body->item['id'][9982a]; // ab
?
xpathis your friend, you can stay with simplexml:
$xml = simplexml_load_string($x); // assume XML in $x
$result = $xml->xpath("/body/item[#id = '9982a']/value")[0]; // requires PHP >= 5.4
echo $result;
Comment:
in PHP < 5.4, do...
$result = $xml->xpath("/body/item[#id = '9982a']/value");
$result = $result[0];
see it working: https://eval.in/101766
Yes, use Simple HTML DOM Parser instead of SimpleXML.
It would be as easy as:
$xml->find('item[id="9982b"]',0)->find('value',0)->innertext;
It is possible with DOMXpath::evaluate() to fetch scalar values from a DOM using xpath expressions:
$xml = <<<'XML'
<body>
<item id="9982a">
<value>ab</value>
</item>
<item id="9982b">
<value>abc</value>
</item>
</body>
XML;
$dom = new DOMDocument;
$dom->loadXml($xml);
$xpath = new DOMXpath($dom);
var_dump(
$xpath->evaluate('string(//body/item[#id="9982b"]/value)')
);
Consider the following code :
$dom = new DOMDocument();
$dom->loadXML($file);
$xmlPath = new DOMXPath($dom);
$arrNodes = $xmlPath->query('*/item');
foreach($arrNodes as $item){
//missing code
}
The $file is an xml and each item has a title and a description.
How can I display them (title and description)?
$file = "<item>
<title>test_title</title>
<desc>test</desc>
</item>";
I suggest using php's simplexml, with that, you still get xpath functionality, but with easier approach, for example you would access attributes like this:
$name = $item['name'];
Here's an example:
xmlfile.xml:
<?xml version="1.0" encoding="UTF-8"?>
<xml>
<items>
<item title="Hello World" description="Hellowing the world.." />
<item title="Hello People" description="greeting people.." />
</items>
</xml>
do.php:
<?php
$xml_str = file_get_contents('xmlfile.xml');
$xml = new SimpleXMLElement($xml_str);
$items = $xml->xpath('*/item');
foreach($items as $item) {
echo $item['title'], ': ', $item['description'], "\n";
}
If your item looks like this:
<item>
<title>foo</title>
<description>frob</description>
</item>
You could use getElementsByTagName() and nodeValue:
foreach($arrNodes as $item){
print $item->getElementsByTagName('title')->item(0)->nodeValue;
}
Are title and description attributes? E. g. does an item look like this:
<item title="foo" description="frob" />
If so, you could just use getAttribute():
...
foreach($arrNodes as $item){
print $item->getAttribute('title');
}
The right XPath expression should be:
/*/item/title | /*/item/desc
Or
/*/item/*[self::title or self::desc]
This is evaluate to a node set with title and desc element in document order