I have this code
$xml = $mbpay->processPaymentInfo();
Log::info('Showing $mbpay:' . var_export($xml, true));
The log shows like:
[2018-07-06 12:40:56] local.INFO: Showing $mbpay: '<?xml version="1.0" encoding="ISO-8859-1" ?>
<getmb_id>
<status>ok</status>
<!---->
<doc>000...</doc>
</getmb_id>'
With this xml, I want to get from the notifications table the value of the column "r_id" where the value of the "doc" column is equal to the "doc" element of the $xml above.
Do you know how to properly get the value of the xml element so is possible to do the query to get the r_id?
The query should be something like " $rID = Notifications::where('doc', $doc)->pluck('r_id')->first();
" but how to get the $doc?
updated:
$mbpay = new MBPay($payment_info);
$processed_payment = $mbpay->processPaymentInfo();
$xml = simplexml_load_string($processed_payment);
$doc = $xml->doc;
$rID = DB::table('notifications')->where('doc', $doc)->pluck('r_id')->first();
Log::info('Showing $mbpay: ' . var_export($xml, true));
Log::info('doc: ' . var_export($doc, true)); // shows SimpleXMLElement::__set_state(array(
))
Log::info('rID: ' . var_export($rID, true)); // shows NULL
Log::info('xml: ' . var_export($xml, true));
return \Response::make($xml, '200')->header('Content-Type', 'text/xml');
The $mbpay->processPaymentInfo() shows like:
<?xml version="1.0" encoding="ISO-8859-1" ?>
<getmb_key>
<status>ok</status>
<message>...</message>
<user>...</user>
<doc>...</doc>
</getmb_key>
Assuming you will only ever expect one doc node, there are a few ways you can go about getting the value of the node. The first thing that comes to mind is simplexml_load_string():
$processed_payment = $mbpay->processPaymentInfo();
$xml = simplexml_load_string($processed_payment);
$doc = (string) $xml->doc;
We can also parse it with DOMDocument's loadXML():
$dom = new \DOMDocument();
$dom->loadXML($processed_payment);
$docs = $dom->getElementsByTagName('doc');
$doc = $docs->item(0)->nodeValue;
As well as with SimpleXMLElement::
$element = new \SimpleXMLElement($processed_payment);
$doc = (string) $element->doc[0];
Finally, there's good old regex with preg_match:
$result = preg_match("/<doc>(.*?)<\\/doc>/", $processed_payment, $matches);
var_dump($matches[1]);
Which method you use depends on the structure of your document and, somewhat, your personal preference. For me, simplexml_load_string() was the first thing that came to mind, but after considering alternatives and given the knowledge of the expected structure, I think I'd prefer SimpleXMLElement().
Here are working examples of each method above.
Related
Given the XML and related PHP, below how can I get the namespaced values in the same way that I'm able to get the non-namespaced values? I've been referring to a number of other SE QAs about this, but can't seem to get it right. An help is appreciated. :)
<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:psg="http://b3000.example.net:3000/psg_namespace/">
<channel>
<title>Example</title>
<description>example stuff</description>
<item>
<psg:eventId>406589</psg:eventId>
<psg:duration>3482</psg:duration>
</item>
</channel>
</rss>
$xml = new SimpleXMLElement($source, null, true);
foreach($xml->channel->item as $entry){
echo $entry->title; // This works
echo $entry->description; // This works
echo $entry->item->duration // Pseudo of what I need
}
How to get Duration? My attempts with variations such as this have failed
$namespaces = $item->getNameSpaces(true);
$psg = $item->children($namespaces['psg']);
Update
While it wasn't the answer I was actually looking for, I have to accept the first answer that got me trying things leading to the actual problem - "operator error"! This DOES work....my problem was in trying to figure it out, I was debugging with echo print_r($psg, true). That was showing the result as a SimpleXmlObject, which then got me chasing how to get those properties - All I had to do was assign the property instead of echoing it.
foreach($xml->channel->item as $entry){
$psg = $item->children($ns['psg']);
$title = (string) $item->title;
$duration = (string) $psg->duration;
}
One way to achieve this is to use a combination of XPath with namespaces:
$xml = new SimpleXMLElement($source, null, true);
$xml->registerXPathNamespace('psg', 'http://b3000.example.net:3000/psg_namespace/');
foreach ($xml->xpath('//item/psg:duration') as $duration) {
echo $duration, PHP_EOL;
}
If you don't want to declare the namespace literally, you can retrieve it from the document and add it/them dynamically:
foreach ($xml->getDocNamespaces() as $key => $namespace) {
$xml->registerXPathNamespace($key, $namespace);
}
Im attempting to echo/assign a variable to the contents of the node "code" which is inside status;
I can get request-id just fine...
Any ideas people?
<?
$responseXML = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<payment xmlns="http://www.example.com" self="http://www.example.com">
<merchant-account-id ref="http://www.example.com">0000</merchant-account-id>
<transaction-id>0000</transaction-id>
<request-id>0000</request-id>
<transaction-type>auth</transaction-type>
<transaction-state>success</transaction-state>
<completion-time-stamp>2015-12-28T17:39:25.000Z</completion-time-stamp>
<statuses>
<status code="201.0000" description="3d-acquirer:The resource was successfully created." severity="information"/>
</statuses>
<avs-code>P</avs-code>
<requested-amount currency="GBP">0.01</requested-amount>
<account-holder>
<first-name>test</first-name>
<last-name>test</last-name>
<email>test.test#hotmail.co.uk</email>
<phone>00000000000</phone>
<address>
<street1>test</street1>
<city>test test</city>
<state>test</state>
<country>GB</country>
</address>
</account-holder>
<card-token>
<token-id>000</token-id>
<masked-account-number>000000******0000</masked-account-number>
</card-token>
<ip-address>192.168.0.1</ip-address>
<descriptor></descriptor>
<authorization-code>000000</authorization-code>
<api-id>000-000</api-id>
</payment>';
$doc = new DOMDocument;
$doc->loadXML($responseXML);
echo $doc->getElementsByTagName('request-id')->item(0)->nodeValue;
echo $doc->getElementsByTagName('status code')->item(0)->nodeValue;
?>
I've tried simplexml looad string, but pulling hair out with this one, can anybody shed some light, speed of getting this info out in one process is quite important so not to stress the webserver out!
Many thanks.
Using DOM is a good idea, but the API methods are a little cumbersome. Using Xpath makes it a lot easier.
Xpath allows you to use expressions to fetch node lists or scalar values from a DOM:
$document = new DOMDocument;
$document->loadXML($responseXML);
$xpath = new DOMXpath($document);
$xpath->registerNamespace('example', 'http://www.example.com');
echo $xpath->evaluate('string(//example:request-id)'), "\n";
echo $xpath->evaluate('string(//example:status/#code)');
Output:
0000
201.0000
Xpath does not have a default namespace so if you XML has a namespace (like your example) you need to register a prefix for it and use it.
As code is an attribute of xml tag status, doing
getElementsByTagName('status code')
is wrong.
There's a special method for getting attribute value getAttribute:
echo $doc->getElementsByTagName('status')->item(0)->getAttribute('code');
Using XPath allows to access the status node very precisely.
DOMDocument + XPath:
$responseXML = '...';
$doc = new DOMDocument();
$doc->loadXML($responseXML);
$xp = new DOMXpath($doc);
$xp->registerNamespace('example', 'http://www.example.com');
// Every status node.
$statusNodes = $xp->query('//example:status');
// or a very specific one.
$statusNodes = $xp->query('/example:payment/example:statuses/example:status');
$statusNode = $statusNodes[0];
$code = $statusNode->getAttribute('code');
// $code is '201.0000'.
// To change the 'code' value.
$statusNode->setAttribute('code', '302.0000');
I'm creating XML response for the one of our clients with the namespace URLs in that using PHP. I'm expecting the output as follows,
<?xml version="1.0" encoding="UTF-8"?>
<ns3:userResponse xmlns:ns3="http://www.w3.org/2001/XMLSchema-instance" xmlns:ns2="http://www.w3.org/2001/XMLSchema">
<Content>
<field1>fieldvalue1</field1>
</Content>
</ns3:userResponse>
But by using the following code,
<?php
// create a new XML document
$doc = new DomDocument('1.0', 'UTF-8');
// create root node
$root = $doc->createElementNS('http://www.w3.org/2001/XMLSchema-instance', 'ns3:userResponse');
$root = $doc->appendChild($root);
$root->setAttributeNS('http://www.w3.org/2001/XMLSchema-instance', 'ns1:schemaLocation','');
$root->setAttributeNS('http://www.w3.org/2001/XMLSchema', 'ns2:schemaLocation','');
// add node for each row
$occ = $doc->createElement('Content');
$occ = $root->appendChild($occ);
$child = $doc->createElement("field1");
$child = $occ->appendChild($child);
$value = $doc->createTextNode('fieldvalue1');
$value = $child->appendChild($value);
// get completed xml document
$xml_string = $doc->saveXML();
echo $xml_string;
DEMO:
The demo is here, http://codepad.org/11W9dLU9
Here the problem is, the third attribute is mandatory attribute for the setAttributeNS PHP function. So, i'm getting the output as,
<?xml version="1.0" encoding="UTF-8"?>
<ns3:userResponse xmlns:ns3="http://www.w3.org/2001/XMLSchema-instance" xmlns:ns2="http://www.w3.org/2001/XMLSchema" ns3:schemaLocation="" ns2:schemaLocation="">
<Content>
<field1>fieldvalue1</field1>
</Content>
</ns3:userResponse>
So, is there anyway to remove that ns3:schemaLocation and ns2:schemaLocation which is coming with empty value? I googled a lot but couldn't able to find any useful answers.
Any idea on this would be so great. Please help.
You create this attributes:
$root->setAttributeNS('http://www.w3.org/2001/XMLSchema-instance', 'ns1:schemaLocation','');
$root->setAttributeNS('http://www.w3.org/2001/XMLSchema', 'ns2:schemaLocation','');
remove this lines and they will be removed.
If you want to add some xmlns without using it in code is:
$attr_ns = $doc->createAttributeNS( 'http://www.w3.org/2001/XMLSchema', 'ns2:attr' );
Read this comment: http://php.net/manual/pl/domdocument.createattributens.php#98210
$xml = '<?xml version="1.0" encoding="UTF-8"?>
<stw:ThumbnailResponse xmlns:stw="http://www.shrinktheweb.com/doc/stwresponse.xsd">
<stw:Response>
<stw:ThumbnailResult>
<stw:Thumbnail Exists="true">http://imagelink.com</stw:Thumbnail>
<stw:Thumbnail Verified="false">delivered</stw:Thumbnail>
</stw:ThumbnailResult>
<stw:ResponseStatus>
<stw:StatusCode>refresh</stw:StatusCode>
</stw:ResponseStatus>
<stw:ResponseTimestamp>
<stw:StatusCode>1413812009</stw:StatusCode>
</stw:ResponseTimestamp>
<stw:ResponseCode>
<stw:StatusCode>HTTP:200</stw:StatusCode>
</stw:ResponseCode>
<stw:CategoryCode>
<stw:StatusCode></stw:StatusCode>
</stw:CategoryCode>
<stw:Quota_Remaining>
<stw:StatusCode>132</stw:StatusCode>
</stw:Quota_Remaining>
<stw:Bandwidth_Remaining>
<stw:StatusCode>999791</stw:StatusCode>
</stw:Bandwidth_Remaining>
</stw:Response>
</stw:ThumbnailResponse>';
$dom = new DOMDocument;
$dom->loadXML($xml);
$result = $dom->getElementsByTagName('stw:Thumbnail')->item(0)->nodeValue;
$status = $dom->getElementsByTagName('stw:Thumbnail')->item(0)->nodeValue;
echo $result;
Having the above code should output http://imagelink.com and $status should hold "delivered" - but none of these work instead I am left with the error notice that:
Trying to get property of non-object
I have tried different xml parsing alternatives like simplexml (but that did not work when the tag names have : in it ) and i tried looping through the each scope in the xml (ThumbNailresponse, response and then thumbnailresult) without luck.
How can i get the values inside stw:Thumbnail?
You need to specify a namespace and the method DOMDocument::getElementsByTagName can't handle it. In the manual:
The local name (without namespace) of the tag to match on.
You can use DOMDocument::getElementsByTagNameNS instead:
$dom = new DOMDocument;
$dom->loadXML($xml);
$namespaceURI = 'http://www.shrinktheweb.com/doc/stwresponse.xsd';
$result = $dom->getElementsByTagNameNS($namespaceURI, 'Thumbnail')->item(0)->nodeValue;
Using simple xml you could use ->children() method on this one:
$xml = simplexml_load_string($xml_string);
$stw = $xml->children('stw', 'http://www.shrinktheweb.com/doc/stwresponse.xsd');
echo '<pre>';
foreach($stw as $e) {
print_r($e);
// do what you have to do here
}
This code actually runs just fine for me ---
Typically, that sort of error means you may've made a typo on your $dom object - double check it and try again.
Also, it is notable that you'll want to change the item(0) to item(1) when you're setting your $status variable.
$result = $dom->getElementsByTagName('stw:Thumbnail')->item(0)->nodeValue;
$status = $dom->getElementsByTagName('stw:Thumbnail')->item(0)->nodeValue;
I can't seem to get anything to work with simpleXML for PHP. What is wrong with the following:
$xml = simplexml_load_string('<book><title>The Title</title></book>');
$title = $xml->book->title;
echo "<pre>title = $title\n</pre>";
The resulting output is:
title =
Why isn't the output as follows?
title = The Title
Please advise.
Since <book> is the root node of this snippet, you need $xml->title rather than $xml->book->title.
$xml = simplexml_load_string('<book><title>The Title</title></book>');
$title = $xml->title;
echo "<pre>title = $title\n</pre>";
// Prints
<pre>title = The Title
</pre>
The structure is more easily discovered if you var_dump() it:
var_dump($xml);
object(SimpleXMLElement)#1 (1) {
["title"]=>
string(9) "The Title"
}
Try
$str = '<book><title>The Title</title></book>';
$xml = new SimpleXMLElement($str);
$title = $xml->book->title;
echo $title;
What I suspect the problem being is that you haven't created the XML object and are trying to use a method from that object. Thats my assumption given your code snippet.
Take a look at PHP: Simple XML