PHP DomXPath - "object value omitted" even if new DomDocument is not empty? - domxpath

I have a xml file like this...
XML File
<?xml version="1.0" encoding="UTF-8"?>
<database xmlns="tt:foo" xmlns:h4a="https://www.myexample.com/foo.xsd" >
<tables>
<table name="my_first_table_name">
<column name="column_name_1" />
</table>
</tables>
</database>
I 'm trying to use DOMXPath for a future xml merging.
PHP Code
$doc_ref = new \DOMDocument();
$doc_ref->load( $array_xml_paths[0] );
$xpath_ref = new \DOMXPath($doc_ref);
error_log_array( $xpath_ref );
foreach ($xpath_ref->evaluate('//table[#name]') as $table) {
$table_name = $table->getAttribute('name');
error_log( $table_name );
}
output
[08-Mar-2018 14:21:47 UTC] DOMXPath Object
(
[document] => (object value omitted)
)
The DOMDocument is correclty loaded, but something more seems to be necessary for DOMXPath to work it but I don't know.

First of all...
[document] => (object value omitted) DOES NOT MEAN the DOMXPath instance is empty !
I found the solution. It was in this comment.
I had to register the xml namespace to use evaluate().
Solution
$doc_ref = new \DOMDocument();
$doc_ref->load( $array_xml_paths[0] );
$xpath_ref = new \DOMXPath( $doc_ref );
$ns = $doc_ref->documentElement->namespaceURI;
if($ns) {
$xpath_ref->registerNamespace("ns", $ns);
foreach ($xpath_ref->evaluate('//ns:table[#name]') as $table) {
$table_name = $table->getAttribute('name');
error_log( $table_name );
}
}else {
foreach ($xpath_ref->evaluate('//table[#name]') as $table) {
$table_name = $table->getAttribute('name');
error_log( $table_name );
}
}

Related

Postman REST API: Compare two XML response

I am trying to compare XML reponse of 2 REST API's. I wanted to compare few fields from Response1 to Response2.
Response1:
<d:site_name>Bondi Junction</d:site_name>
<d:country>AU</d:country>
<d:regio>NSW</d:regio>
<d:contact>123456789</d:contact>
Response2:
<d:country>AU</d:country>
<d:region>NSW</d:region>
I have created a Collection which will have both API's and I wanna run both API's and compare the available columns ( I don't want to compare completely).
Could you please guide me an approach to done.
Thanks,
Sekar
enter image description here
As far as I know, there's no easy way to compare values of xml attributes and elements without converting the xml to json.
Below is a working example(xml converted to json) for 2 use-cases (test)
Using the function difference(), you can test if the 2 xmls have any differences.
Using json path to extract the value of xml elements you can also compare specific field values
function difference(object, base) {
function changes(object, base) {
return _.transform(object, function(result, value, key) {
if (!_.isEqual(value, base[key])) {
result[key] = (_.isObject(value) && _.isObject(base[key])) ? changes(value, base[key]) : value;
}
});
}
return changes(object, base);
}
var xml1 = `<?xml version=\"1.0\" encoding=\"UTF-8\"?>
<envelope>
<body>
<d:site_name>Bondi Junction</d:site_name>
<d:country>AU</d:country>
<d:regio>NSW</d:regio>
<d:contact>123456789</d:contact>
</body>
</envelope>
`;
var xml2 = `<?xml version=\"1.0\" encoding=\"UTF-8\"?>
<envelope>
<body>
<d:country>AU</d:country>
<d:region>NSW</d:region>
</body>
</envelope>
`;
var jsonObject1 = xml2Json(xml1);
var jsonObject2 = xml2Json(xml2);
var diff = difference(jsonObject1, jsonObject2);
console.log(diff);
pm.test("Test for any differences in the 2 payloads", function() {
//diff object will be empty in case of no differences
pm.expect(_.isEmpty(diff)).to.eql(true);
});
pm.test("Test for the value of country in 2 payloads ", function() {
pm.expect(jsonObject1.envelope.body.country).to.eql(jsonObject2.envelope.body.country);
});

Http body empty when adding customer via prestashop webservice

I'm trying to add a new customer via webservice to my prestashop database but in appearance, everything is OK, returned code 200 but response xml body is empty and database has no new customers.
I've enabled webservice for the GET and PUT crud methods and generate API Key.
Code for the customer addition is the next one:
require_once('../../../lib/PSWebServiceLibrary.php');
$id_customer = 0;
$id_address = 0;
$id_cart = 0;
$date_now = date("Y-m-d H:i:s");
try {
$webService = new PrestaShopWebservice(PS_SHOP_PATH, PS_WS_AUTH_KEY, DEBUG);
foreach ($pedidos->orders as $ord) {
if (!$id_customer) {
// Getting the empty XML document to send back completed
$xml = $webService->get(array('url' => PS_SHOP_PATH . 'api/customers?schema=blank'));
// Adding dinamic values
// Required
$xml->customer->passwd = Tools::encrypt($password = 'mypassword');
$xml->customer->lastname = $ord->customer->lastname;
$xml->customer->firstname = $ord->customer->firstname;
$xml->customer->email = $ord->customer->customer_id.'#example.com';
// Others
$xml->customer->id_lang = 1;//$id_lang;
$xml->customer->id_shop = 1;
$xml->customer->id_shop_group = 1;
$xml->customer->id_default_group = 3;//$id_group; // Customers
$xml->customer->active = 1;
$xml->customer->newsletter = 0;
$xml->customer->newsletter_date_add = $date_now;
$xml->customer->last_passwd_gen = $date_now;
$xml->customer->date_add = $date_now;
$xml->customer->date_upd = $date_now;
$xml->customer->id_gender = 0;
$xml->customer->associations->groups->group[0]->id = 3; // customers
// Adding the new customer
$opt = array('resource' => 'customers');
$opt['postXml'] = $xml->asXML();
$xml = $webService->add($opt);
$id_customer = $xml->customer->id;
}
}
}catch (PrestaShopWebserviceException $e) {
// Here we are dealing with errors
$trace = $e->getTrace();
if ($trace[0]['args'][0] == 404) echo 'Bad ID';
else if ($trace[0]['args'][0] == 401) echo 'Bad auth key';
else echo 'Other error<br />'.$e->getMessage();
}
When executed, this one returns a code 200 but the response body is completely empty.
<?xml version="1.0" encoding="UTF-8"?>
<prestashop xmlns:xlink="http://www.w3.org/1999/xlink">
<customer>
<id></id>
<id_default_group></id_default_group>
<id_lang></id_lang>
<newsletter_date_add></newsletter_date_add>
<ip_registration_newsletter></ip_registration_newsletter>
<last_passwd_gen></last_passwd_gen>
<secure_key></secure_key>
<deleted></deleted>
<passwd></passwd>
<lastname></lastname>
<firstname></firstname>
<email></email>
<id_gender></id_gender>
<birthday></birthday>
<newsletter></newsletter>
<optin></optin>
<website></website>
<company></company>
<siret></siret>
<ape></ape>
<outstanding_allow_amount></outstanding_allow_amount>
<show_public_prices></show_public_prices>
<id_risk></id_risk>
<max_payment_days></max_payment_days>
<active></active>
<note></note>
<is_guest></is_guest>
<id_shop></id_shop>
<id_shop_group></id_shop_group>
<date_add></date_add>
<date_upd></date_upd>
<associations>
<groups>
<group>
<id></id>
</group>
</groups>
</associations>
</customer>
</prestashop>
Anyone knows why is this happening? Thanks for your time.
Asked myself. In my case explained on top, I need one webservice per order so:
$webService = new PrestaShopWebservice(PS_SHOP_PATH, PS_WS_AUTH_KEY, DEBUG);
This line must be inside foreach iteraction.

pass xml variable into c# method in xslt

i have xslt transform where im using c# code to save input and output xml to database.
but it saves only the values of all tags.
but i want to save vhole xml.
<msxsl:script language="CSharp" implements-prefix="ConnectDatabase">
<msxsl:assembly name = "System.Data"/>
<msxsl:using namespace = "System.Data"/>
<msxsl:using namespace = "System.Data.SqlClient"/>
<msxsl:using namespace = "System.Collections.Generic"/>
<![CDATA[
public void LogINOUT(string inputxml, string outputxml)
{
SqlCommand cmd = null;
string command = "INSERT INTO dbo.XsltLog (InputXml,OutputXml) VALUES (#inputxmlpar,#outputxmlpar)";
string connectionString ="Data Source=MyConneCtionStiring;
SqlParameter inputxmlpar = new SqlParameter("#inputxmlpar", SqlDbType.NVarChar);
inputxmlpar.Value=inputxml;
SqlParameter outputxmlpar = new SqlParameter("#outputxmlpar", SqlDbType.NVarChar);
outputxmlpar.Value =outputxml;
using (SqlConnection connection = new SqlConnection(connectionString))
{
cmd = new SqlCommand(String.Format(command), connection);
cmd.Parameters.Add(inputxmlpar);
cmd.Parameters.Add(outputxmlpar);
connection.Open();
cmd.ExecuteScalar();
}
}
]]></msxsl:script>
then a call it <xsl:copy-of select ="ConnectDatabase:LogINOUT( $inputxml,$outputxml)" />
and outputxml in database is something like this:
TO_TESTY45000.0000000020
from this string i know nothing
i wont its
<Data>
<Result>TO_TEST</Result>
<IncludeInVolume>Y</IncludeInVolume>
<FinancedAmont>
<xsl:value-of select="/Contract/ContractCalculations/Calculation/CalculationStep[#Code='FinancedAmount']"/>
</FinancedAmont>
<NumberOfInstalments>
<xsl:value-of select="format-number(/Contract/ContractCalculations/Calculation/CalculationStep[#Code='InstalmentNumber'],'#')"/>
</NumberOfInstalments>
</Data>
the same problem its with inputxml
thanks for Help Dana

TinyXML2 query text if attribute matches

I am trying to figure out a way to load the text from an XML document I have created using TinyXML2. Here is the entire document.
<?xml version="1.0" encoding="UTF-8"?>
<map version="1.0" orientation="orthogonal" width="15" height="13" tilewidth="32" tileheight="32">
<tileset firstgid="1" name="Background" tilewidth="32" tileheight="32">
<image source="background.png" width="64" height="32"/>
</tileset>
<tileset firstgid="3" name="Block" tilewidth="32" tileheight="32">
<image source="block.png" width="32" height="32"/>
</tileset>
<layer name="Background" width="15" height="13">
<data encoding="base64">
AgAAAAIAAAACAAAA...
</data>
</layer>
<layer name="Block" width="15" height="13">
<data encoding="base64">
AwAAAAMAAAADAAAAAwAAAAM...
</data>
</layer>
</map>
Basically, I want to copy the text from <data> into a string called background only if the layer name is "Background".
I have gotten the other variables like so:
// Get the basic information about the level
version = doc.FirstChildElement("map")->FloatAttribute("version");
orientation = doc.FirstChildElement("map")->Attribute("orientation");
mapWidth = doc.FirstChildElement("map")->IntAttribute("width");
mapHeight = doc.FirstChildElement("map")->IntAttribute("height");
That works great because I know the element name and the attribute name. Is there a way to say get the doc.FirstChildElement("map")->FirstChildElement("layer") and if it == "Background", get the text.
How would I accomplish this?
I know this thread is quite old, but just in case someone perusing the internet might stumble upon this question as I have, I wish to point out that Xanx's answer can be simplified slightly.
In tinyxml2.h it says that for the function const char* Attribute( const char* name, const char* value=0 ) const, if the value parameter is not null, then the function only returns if value and name match. According to the comments in the file this:
if ( ele->Attribute( "foo", "bar" ) ) callFooIsBar();
can be written like this:
if ( ele->Attribute( "foo" ) ) {
if ( strcmp( ele->Attribute( "foo" ), "bar" ) == 0 ) callFooIsBar();
}
So the code Xanx provided can be rewritten like this:
XMLElement * node = doc.FirstChildElement("map")->FirstChildElement("layer");
std::string value;
if (node->Attribute("name", "Background")) // no need for strcmp()
{
value = node->FirtChildElement("data")->GetText();
}
A minor change, yes, but something I wanted to add.
I advice you to do something like this:
XMLElement * node = doc.FirstChildElement("map")->FirstChildElement("layer");
std::string value;
// Get the Data element's text, if its a background:
if (strcmp(node->Attribute("name"), "Background") == 0)
{
value = node->FirtChildElement("data")->GetText();
}
auto bgData = text (find_element (doc, "map/layer[#name='Background']/data"));
Using tinyxml2 extension (#include <tixml2ex.h>).
N.B. should really be wrapped in a try/catch block.
Work in progress and documentation is incomplete (can deduce from the test example until it's ready).
I'll mention in passing that the other two answers only work properly when the desired <layer> element appears first.

problem with XSLT

I am trying to create a html based template with xslt transformation.The string result returned by the transformer is perfectly fine.but when i try to send it to display, the browser is not interpreting it. The output looks like<html><body>...</body></html>.
when i do view source it is displaying <html>... How can i resolve it?Please help.
Thanks in advance
Did you specify the output method correctly? It should be set to HTML:
<xsl:output method="html" encoding="UTF-8" />
<xsl:output value="html"/>
<xsl:template match="mail[#type='pinReset']">
<html><body>
<xsl:variable name="userService" select="java:new()"/>
<i><u>Message body </u><xsl:value-of select="mailMessage/mail/body/prefix"/></i>
<a><xsl:attribute name="href">
<xsl:value-of select="java:getResetPinUrl($userService)"/></xsl:attribute>
reset pin
</a>
<i><xsl:value-of select="mailMessage/body/suffix"/></i><br/>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
This is my XSl.
public String getXformedString(int type){
String xFormedString = "";
String xsltFile = "D:\\SitesContent\\sitescontent_war\\JavaSource\\com\\tgt\\mobile\\gc\\controller\\email.xsl";
String xmlFile="D:\\SitesContent\\sitescontent_war\\JavaSource\\com\\tgt\\mobile\\gc\\controller\\emailBody.xml";
StringWriter stWr = new StringWriter();
File xsltfile = new File(xsltFile);
File xmlfile = new File(xmlFile);
Source xmlSource = new StreamSource(xmlfile);
Source xsltSource = new StreamSource(xsltfile);
Result result = new StreamResult(stWr);
TransformerFactory transFact = TransformerFactory.newInstance();
try {
Transformer transformer= transFact.newTransformer(xsltSource);
transformer.setParameter("type",new Integer(type));
transformer.transform(xmlSource, result);
xFormedString = stWr.toString();
System.out.println("Str->"+xFormedString);
} catch (TransformerConfigurationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (TransformerException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return xFormedString;
}
This is the code to get the formed string from xml and xslt.