read XML tag id from php - php

i am have the following XML file
<?xml version="1.0" encoding="iso-8859-1"?>
<Message Id="Language">German</Message>
<Message Id="LangEnglish">German</Message>
<Message Id="TopMakeHomepage">
Mache 4W Consulting Webseite zu deiner Starseite!
</Message>
<Message Id="TopLinkEmpSec">
4W Mitarbeiter
</Message>
<Message Id="TopLinkFeedback">
Feedback
</Message>
<Message Id="TopLinkSiteMap">
Site Map
</Message>
<Message Id="TopLinkContactUs">
Kontakt
</Message>
<Message Id="TopSetLangEn">
ins Englische
</Message>
<Message Id="TopSetLangDe">
ins Deutsche
</Message>
<Message Id="TopSetLangEs">
ins Spanische
</Message>
<Message Id="MenuLinks">
!~|4W Starseite|Company|Über uns|Kontakt|4W anschließen|Services|Kunden Software Entwicklung|Altsystem Neugestalltung & Umwandlung|Altsystem Dokumentation|Daten Umwandlung & Migration|Erstellen von Datenbeschreibungsverzeichnis|System- & Anwendungs Support|Projekt Management & Planunng|Personal Erweiterung|Projekt Ausgliederung|Mitarbeiter Ausbildung|Technologie|Intersystems Caché|M / MUMPS|Zusätzliche Technologien|Methodologie|Feedback|~!
</Message>
</MsgFile>
in this XML file i need to fetch the contents using the tagid . what exactly i need is when i input the 'TopMakeHomepage' i need output as 'Mache 4W Consulting Webseite zu deiner Starseite!' ...
Please help me to find out this . Thanks in advance

Use SimpleXML:
$xml = simplexml_load_file($grabUrl);
foreach ($xml->Message as $message) {
echo $message->attributes()->Id.'<br />';
}
Or use XMLReader, with which you can miss memory leaks when processing large XMLs.
$xml = new XMLReader;
$xml->open($grabUrl);
while ($xml->read()) {
if ($xml->nodeType === XMLReader::ELEMENT && $xml->name == 'Message')
echo $xml->getAttribute('Id');
}

With the DOM extension it should be something like this:
$dom = new DOMDocument;
$dom->validateOnParse = TRUE;
$dom->loadXML($xmlString); // or use ->load('file.xml')
$node = $dom->getElementById('foo');
echo $node->nodeValue;
See the manual on
DOMDocument::getElementById — Searches for an element with a certain id
If it doesn't work with getElementById (which usually only happens if the DTD doesn't know the id attribute), you can still use XPath to do the query:
$xpath = new DOMXPath($dom);
$nodes = $xpath->query('//Message[#id = "foo"]');
foreach($nodes as $node) {
echo $node->nodeValue;
}
Unlike getElementById, an XPath query always returns a DOMNodeList. It will be empty if the query didn't find any nodes.
If the ID is a real XML ID, you can also use the id() function in XPath
$xpath = new DOMXPath($dom);
$nodes = $xpath->query('id("foo")');
foreach($nodes as $node) {
echo $node->nodeValue;
}
See Simplify PHP DOM XML parsing - how? for more details on XML IDs.

For SimpleXML this should do the trick:
$xml = simplexml_load_file($xmlFileLoc);
foreach ($xml->Message as $msg)
{
echo $msg['Id'];
}

Related

How can I find an xml string using php in this case?

I want my php-script to download files from a specific link based on xml id's. I want it to ignore the rest of the xml-code, I want it to just look at the first id of every lib.
My xml looks like this:
**
<lib id="ITEM_I_WANT_TO_DOWNLOAD_1" revision="0000">
<part id="0000" type="ch"/>
<part id="0000" type="ls"/>
<part id="0000" type="rs"/>
<part id="0000" type="ch"/>
</lib>
<lib id="ITEM_I_WANT_TO_DOWNLOAD_2" revision="0000">
<part id="0000" type="ch"/>
<part id="0000" type="ls"/>
<part id="0000" type="rs"/>
<part id="0000" type="ch"/>
</lib>
**
My current PHP-script looks like this:
if (!defined('STDIN'))
{
echo 'Please run it as a cmd ({path to your php}/php.exe {path to badges.php} -f)';
exit;
}
define('BASE', 'https://randomtarget.com/');
$figuremap = get_remote_data('https://random/xmlfile-needed.xml/');
if (!file_exists('C:/outputfolder/')) {
mkdir('C:/outputfolder/', 0777, true);
echo "\n --------------> Output folder has been made... \n";
sleep(3);
$fp = fopen("C:/downloaded-xmlfile.xml", "w");
fwrite($fp, $figuremap);
fclose($fp);
echo "\n --------------> XML downloaded and placed into folder \n";
sleep(3);
}
$pos = 0;
while ($pos = strpos($figuremap, '<lib id="', $pos +1))
{
$pos1 = strpos($figuremap, '"', $pos);
$rule = substr($figuremap, $pos, ($pos1 -$pos));
$rule = explode(',', $rule);
$revision = str_replace('">', '', $rule[1]);
$clothing_file = current(explode('*', str_replace('"', '', $rule[2])));
if (file_exists('C:/outputfolder/'.$clothing_file.'.swf'))
{
echo 'Clothing_file found: '.$clothing_file."\r\n";
continue;
}
echo 'Download clothing_file: '.$clothing_file.' '.$revision."\r\n";
if (!#copy(BASE.'/'.$revision.'/'.$clothing_file.'.swf', 'C:/outputfolder'.$clothing_file.'.swf'))
{
echo 'Error downloading: '.$clothing_file."\r\n";
}
}
Beside this code I wrote a get_remote_data function so that's allright. I just want the strpos to grab all the id='' items to check if the files exist on the target-site.
How can I fix it?
There are some easy ways of processing XML files, the easiest (but less flexible) is SimpleXML, the following code should replace the main processing loop...
$xml = simplexml_load_string($figuremap);
foreach ( $xml->lib as $lib ) {
$clothing_file = (string) $lib['id'];
if (file_exists('C:/outputfolder/'.$clothing_file.'.swf'))
{
echo 'Clothing_file found: '.$clothing_file."\r\n";
continue;
}
echo 'Download clothing_file: '.$clothing_file.' '.$revision."\r\n";
if (!#copy(BASE.'/'.$revision.'/'.$clothing_file.'.swf', 'C:/outputfolder'.$clothing_file.'.swf'))
{
echo 'Error downloading: '.$clothing_file."\r\n";
}
}
The start point is to load the XML you have in $figuremap into SimpleXML, then to loop over the elements. This assumes an XML structure of something like...
<lib1>
<lib id="ITEM_I_WANT_TO_DOWNLOAD_1" revision="0000">
<part id="0000a" type="ch" />
<part id="0000" type="ls" />
<part id="0000" type="rs" />
<part id="0000" type="ch" />
</lib>
<lib id="ITEM_I_WANT_TO_DOWNLOAD_2" revision="0000">
<part id="00001" type="ch" />
<part id="0000" type="ls" />
<part id="0000" type="rs" />
<part id="0000" type="ch" />
</lib>
</lib1>
The actual name of the base element doesn't matter as long as the <lib> elements are 1 level down then you can use $xml->lib to loop over them.
Your posted xml string is actually invalid. It needs to be wrapped in a parent element to be repaired. I'm not sure if you are posting your exact xml string or just a section of it.
$xml = '<lib id="ITEM_I_WANT_TO_DOWNLOAD_1" revision="0000">
<part id="0000" type="ch"/>
<part id="0000" type="ls"/>
<part id="0000" type="rs"/>
<part id="0000" type="ch"/>
</lib>
<lib id="ITEM_I_WANT_TO_DOWNLOAD_2" revision="0000">
<part id="0000" type="ch"/>
<part id="0000" type="ls"/>
<part id="0000" type="rs"/>
<part id="0000" type="ch"/>
</lib>';
$xml = '<mydocument>' . $xml . '</mydocument>'; // repair invalid xml
https://stackoverflow.com/q/4544272/2943403
$doc = new DOMDocument();
$doc->loadXml($xml);
$xpath = new DOMXpath($doc);
foreach ($xpath->evaluate('//lib/#id') as $attr) {
$clothing_file = $attr->value;
// perform your conditional actions ...
}
//lib/#id says search for the id attribute of all <lib> elements, anywhere in the document.

Get value of child from the value of another child with the same parent in XML using PHP

I have the following XML document:
<response>
<message>
<badgeid>13</badgeid>
<level>4672</level>
<completion_time>1518626787</completion_time>
<xp>4922</xp>
<scarcity>9717</scarcity>
</message>
<message>
<badgeid>25</badgeid>
<level>1</level>
<completion_time>1480166791</completion_time>
<xp>25</xp>
<scarcity>3761041</scarcity>
</message>
<message>
<badgeid>21</badgeid>
<level>1</level>
<completion_time>1467581153</completion_time>
<xp>100</xp>
<scarcity>16650345</scarcity>
</message>
</response>
I am trying to create a program using PHP that returns the "scarcity" of a certain "badgeid" (that is always unique).
So my question is: How do I get the value of <scarcity></scarcity> when the only input I receive from the user is a unique badgeid? In general words: How do I get the value of a child from the value of another child with the same parent?
You could also use an xpath expression and use the $badgeid as a parameter:
$expression = "/response/message[./badgeid='$badgeid']";
Then you could for example use SimpleXMLElement or DOMDocument.
$data = <<<DATA
<response>
<message>
<badgeid>13</badgeid>
<level>4672</level>
<completion_time>1518626787</completion_time>
<xp>4922</xp>
<scarcity>9717</scarcity>
</message>
<message>
<badgeid>25</badgeid>
<level>1</level>
<completion_time>1480166791</completion_time>
<xp>25</xp>
<scarcity>3761041</scarcity>
</message>
<message>
<badgeid>21</badgeid>
<level>1</level>
<completion_time>1467581153</completion_time>
<xp>100</xp>
<scarcity>16650345</scarcity>
</message>
</response>
DATA;
$badgeid = 25;
$xml = simplexml_load_string($data);
$expression = "/response/message[./badgeid='$badgeid']";
$items = $xml->xpath($expression);
if (count($items) === 1) {
echo $items[0]->scarcity;
}
$doc = new DOMDocument();
$doc->loadXML($data);
$xpath = new DOMXpath($doc);
$res = $xpath->query($expression);
if ($res->length === 1) {
echo $res->item(0)->getElementsByTagName("scarcity")->item(0)->nodeValue;
}
Demo
You could use simplexml_load_string() for an XML string, or simplexml_load_file() if it is a XML file. Then you could iterate over $xml->message and check if $message->badgeid is the item you want :
$xmlstr = '<response>
<message>
<badgeid>13</badgeid>
<level>4672</level>
<completion_time>1518626787</completion_time>
<xp>4922</xp>
<scarcity>9717</scarcity>
</message>
<message>
<badgeid>25</badgeid>
<level>1</level>
<completion_time>1480166791</completion_time>
<xp>25</xp>
<scarcity>3761041</scarcity>
</message>
<message>
<badgeid>21</badgeid>
<level>1</level>
<completion_time>1467581153</completion_time>
<xp>100</xp>
<scarcity>16650345</scarcity>
</message>
</response>';
$badgeid = 21 ; // The value you want to search
$xml = simplexml_load_string($xmlstr);
$scarcity = null ;
foreach ($xml->message as $message) {
if ((string)$message->badgeid == $badgeid) {
$scarcity = (string)$message->scarcity ;
break ;
}
}
// use $scarcity if set.
if (isset($scarcity)) {
// do stuff
echo $scarcity ; // 16650345
}

PHP updating xml CDATA fields with DOMdocument

I have the following XML data:
<?xml version="1.0" encoding="utf-8"?>
<source>
<publisher>some-data</publisher>
<publisherurl>some-data</publisherurl>
<lastBuildDate>a-date</lastBuildDate>
<element>
<sub-element><![CDATA[some-data]]></sub-element>
</element>
</source>
I'm trying to use PHP's built in DOMdocument parser to update the text inside sub-element.
I've tried:
$dom=new DOMDocument();
$dom->load("document.xml");
$ele=$root->getElementsByTagName('element');
foreach ($ele as $e) {
$e->getElementsByTagName('sub-element')->item(0)->nodeValue = "new val";
}
this kind of works but it removes the CDATA and just replaces it with new-val. I want to preserve the CDATA field so I tried the following:
$dom=new DOMDocument();
$dom->load("document.xml");
$ele=$root->getElementsByTagName('element');
foreach ($ele as $e) {
$sub=$e->getElementsByTagName('sub-element');
foreach($sub->childNodes as $child) {
if ($child->nodeType == XML_CDATA_SECTION_NODE) {
$child->nodeValue = 'new-val';
}
}
}
This seems like it should work but PHP returns the following Notice
Undefined property: DOMNodeList::$childNodes
Feel like I'm on the right path but I just can't figure out what I'm doing wrong here. Does anyone know how to fix?
My end goal output is:
<?xml version="1.0" encoding="utf-8"?>
<source>
<publisher>some-data</publisher>
<publisherurl>some-data</publisherurl>
<lastBuildDate>a-date</lastBuildDate>
<element>
<sub-element><![CDATA[new-val]]></sub-element>
</element>
</source>
You need to compare against firstChild
$xml = '<?xml version="1.0" encoding="utf-8"?>
<source>
<publisher>some-data</publisher>
<publisherurl>some-data</publisherurl>
<lastBuildDate>a-date</lastBuildDate>
<element>
<sub-element><![CDATA[some-data]]></sub-element>
</element>
<element>
<sub-element>some-other-data</sub-element>
</element>
</source>';
$dom = new DOMDocument();
$dom->loadXML($xml);
$ele=$dom->getElementsByTagName('element');
foreach ($ele as $e) {
$item = $e->getElementsByTagName('sub-element')->item(0);
if($item->firstChild->nodeType == XML_CDATA_SECTION_NODE) { //<------
//it's CDATA do whatever
$item->firstChild->nodeValue = "new val";
} else {
//it's not , do something else
$item->nodeValue = "new val";
}
}
echo "<pre>";
print_r(htmlentities($dom->saveXML()));
echo "</pre>";
Output:
<?xml version="1.0" encoding="utf-8"?>
<source>
<publisher>some-data</publisher>
<publisherurl>some-data</publisherurl>
<lastBuildDate>a-date</lastBuildDate>
<element>
<sub-element><![CDATA[new val]]></sub-element>
</element>
<element>
<sub-element>new val</sub-element>
</element>
</source>
PS: if you don't have to make a distinction between CDATA or not, just use firstChild
foreach ($ele as $e) {
$item = $e->getElementsByTagName('sub-element')->item(0);
$item->firstChild->nodeValue = "new val";
}

Parsing XML SOAP response in PHP

I have been trying to parse an XML SOAP response in PHP but I continue to get errors. I cannot figure out why these errors are occuring.
Response from the server, stored in $response as a string (with sensitive data removed):
<?xml version="1.0" encoding="utf-8"?>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Header>
<h:ServerVersionInfo MajorVersion="15" MinorVersion="20" MajorBuildNumber="323" MinorBuildNumber="19" Version="V2017_10_09" xmlns:h="http://schemas.microsoft.com/exchange/services/2006/types" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/>
</s:Header>
<s:Body>
<m:GetAttachmentResponse xmlns:m="http://schemas.microsoft.com/exchange/services/2006/messages" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types">
<m:ResponseMessages>
<m:GetAttachmentResponseMessage ResponseClass="Success">
<m:ResponseCode>NoError</m:ResponseCode>
<m:Attachments>
<t:FileAttachment>
<t:AttachmentId Id="id number"/>
<t:Name>message-footer.txt</t:Name>
<t:ContentType>text/plain</t:ContentType>
<t:ContentId>contentid.prod.outlook.com</t:ContentId>
<t:Content>file contents</t:Content>
</t:FileAttachment>
</m:Attachments>
</m:GetAttachmentResponseMessage>
</m:ResponseMessages>
</m:GetAttachmentResponse>
</s:Body>
</s:Envelope>
My code:
$data = simplexml_load_string($response);
$fileData = $data
->children('s:', true)->Body
->children('m:', true)->GetAttachmentResponse->ResponseMessages->GetAttachmentResponseMessage->Attachments
->children('t:', true)->FileAttachment;
I need to be able to get the file name, content type, and content. I continue to get the following error: Node no longer exists (on line 4 here).
For reference, I have been following this guide: https://joshtronic.com/2014/07/13/parsing-soap-responses-with-simplexml/
Any help is greatly appreciated.
I don't know how to read such a complex XML file with simplexml, but I know that DOMDocument works very well for it.
<?php
$source = file_get_contents('file.xml');
$dom = new DOMDocument("1.0", "UTF-8");
$dom->preserveWhiteSpace = false;
$dom->loadXml($source);
$xpath = new DOMXPath($dom);
$xpath->registerNamespace("s", "http://schemas.xmlsoap.org/soap/envelope/");
$xpath->registerNamespace("m", "http://schemas.microsoft.com/exchange/services/2006/messages");
$xpath->registerNamespace("xsd", "http://www.w3.org/2001/XMLSchema");
$xpath->registerNamespace("xsi", "http://www.w3.org/2001/XMLSchema-instance");
$xpath->registerNamespace("t", "http://schemas.microsoft.com/exchange/services/2006/types");
$fileAttachments = $xpath->query('//m:GetAttachmentResponseMessage/m:Attachments/t:FileAttachment');
/* #var DOMElement $fileAttachment */
foreach ($fileAttachments as $fileAttachment) {
echo 'Name: ' . $xpath->query('t:Name', $fileAttachment)->item(0)->nodeValue . "\n";
echo 'ContentType: ' . $xpath->query('t:ContentType', $fileAttachment)->item(0)->nodeValue . "\n";
echo 'Content: ' . $xpath->query('t:Content', $fileAttachment)->item(0)->nodeValue . "\n";
}

Parsing xml response from ebay getsellerlist with php

I am trying to parse XML with PHP. The XML is a response from ebay getsellerlist api, and is structured like so:
<!--?xml version="1.0" encoding="UTF-8"?-->
<getsellerlistresponse xmlns="urn:ebay:apis:eBLBaseComponents">
<timestamp>2016-08-11T14:17:39.869Z</timestamp>
<ack>Success</ack>
<version>967</version>
<build>E967_CORE_APISELLING_17965876_R1</build>
<itemarray>
<item>
<itemid>itemid1</itemid>
<listingdetails>
<viewitemurl>itemurl1</viewitemurl>
</listingdetails>
<primarycategory>
<categoryid>categoryid1</categoryid>
<categoryname>categoryname1</categoryname>
</primarycategory>
<title>title1</title>
<picturedetails>
<galleryurl>url1</galleryurl>
<photodisplay>thumbnail1</pictureurl>
<pictureurl>picture1</pictureurl>
</picturedetails>
</item>
</itemarray>
</getsellerlistresponse>
My php is as follows:
<?
$xml = '<!--?xml version="1.0" encoding="UTF-8"?--><getsellerlistresponse xmlns="urn:ebay:apis:eBLBaseComponents"><timestamp>2016-08-11T14:17:39.869Z</timestamp><ack>Success</ack><version>967</version><build>E967_CORE_APISELLING_17965876_R1</build><itemarray><item><itemid>itemid1</itemid><listingdetails><viewitemurl>itemurl1</viewitemurl></listingdetails><primarycategory><categoryid>categoryid1</categoryid><categoryname>categoryname1</categoryname></primarycategory><title>title1</title><picturedetails><galleryurl>url1</galleryurl><photodisplay>thumbnail1</pictureurl><pictureurl>picture1</pictureurl></picturedetails></item><item><itemid>itemid2</itemid><listingdetails><viewitemurl>itemurl2</viewitemurl></listingdetails><primarycategory><categoryid>categoryid2</categoryid><categoryname>categoryname2</categoryname></primarycategory><title>title1</title><picturedetails><galleryurl>url2</galleryurl><photodisplay>thumbnail2</pictureurl><pictureurl>picture2</pictureurl></picturedetails></item></itemarray></getsellerlistresponse>';
$dom = new DOMDocument();
$dom->loadXML($xml);
$title_nodes = $dom->getElementsByTagName('title');
$titles = array();
foreach ($title_nodes as $node) {
$titles[] = $node->nodeValue;
echo $node->nodeValue;
}
echo $titles[0];
echo count($titles);
?>
When I run it, I get a blank page, no errors, nothing.
If I check $titles length using count(), it comes back as zero.
For some reason it is not getting the title node (or any other nodes) and I can't figure out how to parse the xml string with php and get the node values.
Any help most appreciated, if the question is vague or lacking detail, please let me know and I will correct it.
The XML isn't valid:
Unable to parse any XML input. org.jdom2.input.JDOMParseException: Error on line 2: The element type "photodisplay" must be terminated by the matching end-tag "".
And that's only after you remove the comments in your XML declaration:
<!--?xml version="1.0" encoding="UTF-8"?-->
shoud be
<?xml version="1.0" encoding="UTF-8"?>
Working demo:
<?php
$xml = '<?xml version="1.0" encoding="UTF-8"?>
<getsellerlistresponse xmlns="urn:ebay:apis:eBLBaseComponents">
<timestamp>2016-08-11T14:17:39.869Z</timestamp>
<ack>Success</ack>
<version>967</version>
<build>E967_CORE_APISELLING_17965876_R1</build>
<itemarray>
<item>
<itemid>itemid1</itemid>
<listingdetails>
<viewitemurl>itemurl1</viewitemurl>
</listingdetails>
<primarycategory>
<categoryid>categoryid1</categoryid>
<categoryname>categoryname1</categoryname>
</primarycategory>
<title>title1</title>
<picturedetails>
<galleryurl>url1</galleryurl>
<photodisplay>thumbnail1</photodisplay>
<pictureurl>picture1</pictureurl>
</picturedetails>
</item>
</itemarray>
</getsellerlistresponse>';
$dom = new DOMDocument();
$dom->loadXML($xml);
$title_nodes = $dom->getElementsByTagName('title');
$titles = array();
foreach ($title_nodes as $node) {
$titles[] = $node->nodeValue;
echo $node->nodeValue;
}
echo $titles[0];
echo count($titles);

Categories