Where is null coming from in this array? - php

I am converting a php array into xml with something like this :
$bigArray = $readConnection->fetchAll($query);
$doc = new DOMDocument();
$doc->formatOutput = true;
$r = $doc->createElement( "DATA" );
$doc->appendChild( $r );
foreach( $bigArray as $product )
{
$b = $doc->createElement( "ITEM" );
$product_type = $doc->createElement( "PRODUCT_TYPE" );
$product_type->appendChild(
$doc->createTextNode( $product['ProductType'] )
);
$b->appendChild( $product_type );
$sku = $doc->createElement( "SKU" );
$sku->appendChild(
$doc->createTextNode( $product['SKU'] )
);
$b->appendChild( $sku );
$r->appendChild( $b );
}
echo $doc->saveXML();
This returns an xml doc however at the very end null is being appended and I think that is what is causing me other problems. So for example at the bottom of the xml that is output it looks like :
</ITEM>
</DATA>
null
This null value is coming from the original array I see if I do:
print_r($bigArray)
I see something like :
Array ( [0] => Array ( [ProductType] => simple [SKU] => 09423100010018 ) [1] => Array ( [ProductType] => simple [SKU] => 14552300010002 )) null
I am calling this from a class in magento like :
class Foo_Model_Queryone extends Mage_Core_Model_Abstract
{
public function pprQuery() {
$resource = Mage::getSingleton('core/resource');
$readConnection = $resource->getConnection('core_read');
$query = ("SELECT cpe.type_id AS 'ProductType',
cpe.sku AS 'SKU',
.....

The Class Mage_Core_Model_Abstract is causing the problem, or another class higher up, that is outputting the null value.
Try to step through it using Xdebug in Netbeans, and see what is causing the null value. I am interested to see the outcome.
HTH

Related

Created a DOMDocument in php that has children with identical names

The XML I am currently trying to build needs to have two <Location> elements, one for origin, one for destination, found in the same parent element. I append the first child without a problem, but the elements that would go to the second child end up on the first.
The DOMDocument is being created with a helper function that excepts data for the current node/children.
public function set_data(Array $data, $root = null){
//Check if element exists
$dom = ($root === null)? $dom = $this->xml : $this->xml->getElementsByTagName($root)->item(0);
//Create the element
$element = ( ! empty( $data['value'] ) ) ? $this->xml->createElement( $data['element'], $data['value'] ): $this->xml->createElement( $data['element']);
//Add any attributes
if ( !empty( $data['attributes'] ) && is_array( $data['attributes'] ) ) {
foreach ( $data['attributes'] as $attribute_key => $attribute_value ) {
$element->setAttribute( $attribute_key, $attribute_value );
}
}
$dom->appendChild($element);
//add children
foreach ( $data as $data_key => $child_data ) {
if(is_array($child_data) && is_numeric($data_key)){
$this->set_data($child_data, $data['element']);
}
}
return true;
}
Input example:
array('element' => 'ShipmentLocations',
array('element' => 'Location',
array('element' => 'LocationType', 'value' => 'Origin'),
array('element' => 'HasLoadingDock', 'value' => 'false')
),
array('element' => 'Location',
array('element' => 'LocationType', 'value' => 'Destination'),
array('element' => 'HasLoadingDock', 'value' => 'true')
)
)...
This function uses getElementsByTagName to see if the element exists, if so then add the child to it. I understand something here needs to be changed. Is there currently a way to explicitly state that the child being added should go to the second element, not the first with the identical name? If not, what would be the best work around for this, can namespaces be added with no problem?
Thanks,

how to pass XML setAttribute in php foreach

I want to generate XML for an array which has many field and i want to set that fields in a single XML element as attributes of that element below is my php code.
<?php
$rs=array();//values come in $rs from database, it has many fields
$doc = new DOMDocument();
$doc->formatOutput = true;
$root = $doc->createElement( "slides" );
$doc->appendChild( $root );
$firstchild = $doc->createElement( "device" );
$fs=$doc->appendChild( $firstchild );
foreach( $rs as $key=>$value ){
$fs->setAttribute($key,$value);
}
$xml_string = $doc->saveXML();
echo $xml_string;
But this is not working for me, it gives me an error like:
DOMElement:setAttribute() expects parameter 2 to be string,array given
My $rs array structure is like:
Array
(
[0] => Array
(
[id] => 1
[name] => dfd
[width] => 2
[height] => 1
[resolution] =>
[space] =>
)
)
, i want output like:
<slides>
<device id="12" name="mydevice" color="red" .....and so on></device>
</slides>
You did some mistakes, the main of them that you appendchild element to Document but not to parent
$doc = new DOMDocument();
$doc->formatOutput = true;
$root = $doc->createElement( "slides" );
$doc->appendChild( $root );
$fs = $doc->createElement( "device" );
$root->appendChild( $fs );
foreach( $rs as $key=>$value ){
$fs->setAttribute($key,$value);
}
$xml_string = $doc->saveXML();
echo $xml_string;
working example
You need to create each attribute and assign it to the correct node, something like this:
foreach( $rs as $key => $value ){
$attrib=$doc->createAttribute($key);
$attrib->nodeValue=$value;
$fs->appendChild( $attrib );
}
The $rs variable is an array of the records with an array of the fields as an element. So you need two nested loops.
The outer loop iterates the records and creates an device element node for each record. The inner loop iterates the fields and adds the attributes.
$rs = [
[
'id' => 1,
'name' => 'dfd',
'width' => 2,
'height' => 1,
'resolution' => '',
'space' => ''
]
];
$document = new DOMDocument();
$slides = $document->appendChild(
$document->createElement("slides")
);
foreach ($rs as $record) {
$device = $slides->appendChild(
$document->createElement("device")
);
foreach($record as $key => $value){
$device->setAttribute($key,$value);
}
}
$document->formatOutput = true;
echo $document->saveXML();
Output:
<?xml version="1.0"?>
<slides>
<device id="1" name="dfd" width="2" height="1" resolution="" space=""/>
</slides>

parseExpression in Twig

I am integrating Twig in an existing project.
I am writing a token parser to parse a custom tag that is similiar to the {% render %} tag.
My tag looks like:
{% mytag 'somestring' with { 'name': name, 'color': 'green' } %}
where name is defined by {% set name = 'foo' %}
I am able to parse somestring without any issues.
This is the code used to parse the stuff in the with{ }:
$Stream = $this->parser->getStream();
if ( $Stream->test( \Twig_Token::NAME_TYPE, 'with' ) )
{
$Stream->next();
$parsedParameters = $this->parser->getExpressionParser()->parseExpression();
$parameters = $this->parser->getEnvironment()->compile( $parsedParameters );
var_dump( $parameters ); //string 'array( "name" => $this->getContext( $context, "name" ), "color" => "green" )' (length=72)
foreach ( $parsedParameters->getIterator() as $parameter )
{
//var_dump($ parameter->getAttribute('value') );
}
}
My goal is to turn 'name': name, 'color': 'green' into an associative array within the token parser:
array(
'name' => 'foo',
'color': 'green',
)
As the documentation is quite sparse and the code in the library is uncommented, I am not sure how to do this. If I loop through $parsedParameters, I get 4 elements consisting of the array key and an array value. However, as name is a variable with a type Twig_Node_Expression_Name, I am unsure as to how I can compile it to get the compiled value. Currently, I have found a way to compile that node, but all it gives me is a string containing a PHP expression which I can't use.
How can I turn the parsed expression into an associative array?
Okey. I guess I was able to solve that. Not to pretty, but should work.
$Stream = $this->parser->getStream();
if ( $Stream->test( \Twig_Token::NAME_TYPE, 'with' ) )
{
$Stream->next();
$parsedParameters = $this->parser->getExpressionParser()->parseExpression();
$parameters = $this->parser->getEnvironment()->compile( $parsedParameters );
var_dump( $parameters ); //string 'array( "name" => $this->getContext( $context, "name" ), "color" => "green" )' (length=72)
$index = null;
$value = null;
foreach ( $parsedParameters->getIterator() as $parameter )
{
if ( $parameter->hasAttribute( 'value' ) )
{
$index = $parameter->getAttribute( 'value' );
}
elseif ( $parameter->hasAttribute( 'name' ) )
{
$value = $parameter->getAttribute( 'name' );
}
if ( isset( $index, $value ) )
{
$params[ $index ] = $value;
$index = null;
$value = null;
}
}
}
So here I have array params, that I can pass to Custom node.
$params = var_export( $properties['params'], true );
unset( $fieldProperties['params'] );
Now I just did following:
$Compiler
->write( "\$params = array();\n" )
->write( "foreach ( {$params} as \$searchFor => \$replaceWith )\n" )
->write( "{\n" )
->write( "\t\$params[ \$searchFor ] = str_replace( \$replaceWith, \$context[\$replaceWith], \$replaceWith );\n" )
->write( "}\n" )
->write( "var_dump( \$params );\n" );
This should be it.
Also I see, that you where talking about TokenParser, but sadly I haven't found the solution to turn it over there.

How to append xml data to xml file without overwriting existing data using php?

HI Guys, Im kinda new to php and xml so pls bear with me.
I wanna how am I gonna append an xml data to an xml file without overwriting the existing data uisng PHP.
I have here the codes:
writexml.php
<?php
$employees = array();
$employees [] = array(
'name' => 'Tom',
'age' => '34',
'salary' => "$10000"
);
$employees [] = array(
'name' => 'Ryan',
'age' => '20',
'salary' => "$2000"
);
$employees [] = array(
'name' => 'Dave',
'age' => '20',
'salary' => "$2000"
);
$doc = new DOMDocument();
$doc->formatOutput = true;
$r = $doc->createElement( "employees" );
$doc->appendChild( $r );
foreach( $employees as $employee )
{
$b = $doc->createElement( "employee" );
$name = $doc->createElement( "name" );
$name->appendChild(
$doc->createTextNode( $employee['name'] )
);
$b->appendChild( $name );
$age = $doc->createElement( "age" );
$age->appendChild(
$doc->createTextNode( $employee['age'] )
);
$b->appendChild( $age );
$salary = $doc->createElement( "salary" );
$salary->appendChild(
$doc->createTextNode( $employee['salary'] )
);
$b->appendChild( $salary );
$r->appendChild( $b );
}
echo $doc->saveXML();
$doc->save("employees.xml")
?>
What happens when I run this code it removes all previous data. Pls help.
You will need to open the existing document to append information to it, your last save will simply overwrite the existing file.
$doc = new DomDocument();
$doc->loadXML(file_get_contents('employees.xml'));
foreach($doc->getElementsByTagName('employees') as $node)
{
// your current xml logic here
}
Update for hafedh
$doc = new DomDocument();
$doc->formatOutput = true;
if($xml = file_get_contents('employees.xml'))
$doc->loadXML($xml);
$nodelist = $doc->getElementsByTagName('employees');
if($nodelist->length === 0)
{
$nodelist = $doc->createElement("employees");
$doc->appendChild($nodelist);
$nodelist = $doc->getElementsByTagName('employees');
}
foreach($nodelist as $key => $node)
{
// Employee Container
$element = $doc->createElement("employee");
$employee = $node->appendChild($element);
// Name Element
$element = $doc->createElement("name");
$name = $employee->appendChild($element);
$element = $doc->createTextNode('CCC');
$name->appendChild($element);
// Age Element
$element = $doc->createElement("age");
$age = $employee->appendChild($element);
$element = $doc->createTextNode('333');
$age->appendChild($element);
}
echo '<pre>' . htmlentities($doc->saveXML());
xml file contents
<employees><employee><name>AAA</name><age>111</age></employee><employee><name>BBB</name><age>222</age></employee></employees>

appending xml data in between nodes using php

$employees = array();
$employees [] = array(
'name' => 'Albert',
'age' => '34',
'salary' => "$1000000000"
);
$employees [] = array(
'name' => 'Claud',
'age' => '20',
'salary' => "$200000000"
);
$doc = new DOMDocument();
$doc->load('xml/text.xml');
$doc->formatOutput = true;
$r = $doc->createElement( "employees" );
$doc->appendChild( $r );
foreach( $employees as $employee )
{
$b = $doc->createElement( "employee" );
$name = $doc->createElement( "name" );
$name->appendChild(
$doc->createTextNode( $employee['name'] )
);
$b->appendChild( $name );
$age = $doc->createElement( "age" );
$age->appendChild(
$doc->createTextNode( $employee['age'] )
);
$b->appendChild( $age );
$salary = $doc->createElement( "salary" );
$salary->appendChild(
$doc->createTextNode( $employee['salary'] )
);
$b->appendChild( $salary );
$r->appendChild( $b );
}
$doc->save("xml/text.xml")
this existing code load and writes data to an xml file, however right now it keeps creating the parent node "employees" over and over again. How would I just append the child nodes to the already existing employees node in the xml file?
Assuming your root node isn't employees, and that there is just one employees node, replace these lines:
$r = $doc->createElement('employees');
$doc->appendChild( $r );
With these:
$tags = $doc->getElementsByTagName('employees');
if ($tags->length) {
$r = $tags->item(0);
} else {
$r = $doc->createElement('employees');
$doc->appendChild( $r );
}
This code uses the first employees node found in the document. If none is found, it appends one to the end of the document. Actually, I'm guessing you want to insert the employees node somewhere inside the document, instead of at the end....
Assuming you already have an XML structure in xml/text.xml with a root node of 'employees' you want to replace this line:
$r = $doc->createElement( 'employees' );
with this line:
$r = $doc->documentElement;

Categories