Log in

View Full Version : Reading, adding, writing xml...unexpected result



I am Abby
04-17-2010, 05:42 PM
I have an .xml with three elements that I use to create an announcement sidebar on my pages.


<sidebar>
<myquote>
<id>1111</id>
<thequote>Hello World</thequote>

<reference>Abby Lee</reference>
</myquote>

</sidebar>

The following code should receive elements from a form, read the.xml, add the new elements on the top, and then write the .xml.
What I get is a new .xml with just the new data. Funny, I would think it would just give me the opposite. I believe I’m close but I just don’t see the problem. Can anyone point me to the problem? Thanks.


//Adding New Announcement
//Item comes from form
if (isset($_POST['iquote']))

{

//Save new Announcement to sidebar.xml

$insertcount = $_POST["newcount"];

$insertquote = $_POST["iquote"];

$insertref = $_POST["iref"];

$idoc = array();

$idoc = new DOMDocument(); 

$idoc->load( '../sidebar.xml' );

$sidebar = array();

$sidebar[] = array(

'id' => $insertcount,

'thequote' => $insertquote,

'reference' => $insertref

);

//Read sidebar.xml and add to array

$isidebar = $idoc->getElementsByTagName( "myquote" );

foreach( $isidebar as $imyquote )

{

$iids = $imyquote->getElementsByTagName( "id" );

$iid = $iids->iten(0) ->nodeValue;

$ithequotes = $imyquote->getElementsByTagName( "thequote" );

$ithequote = $ithequotes->item(0) ->nodeValue;

$ireferences = $imyquote->getElementsByTagName( "reference" );

$ireference = $ireferences->item(0) ->nodeValue;

$sidebar[] = array(

'id' => $iid,

'thequote' => $ithequote,

'reference' => $ireference
 );
}

//rewrite xml
$wdoc = new DOMDocument();

$wdoc ->formatOutput = true;

$w = $wdoc->createElement( 'sidebar' );

$wdoc->appendChild( $w );

foreach ( $sidebar as $myquote )

{

$x = $wdoc->createElement( "myquote" );
$wid = $wdoc->createElement( "id" );

$wid->appendChild(

$wdoc->createTextNode( $myquote[ 'id' ] )

);

$x->appendChild( $wid );

$wthequote = $wdoc->createElement( "thequote" );

$wthequote->appendChild(

$wdoc->createTextNode( $myquote[ 'thequote' ] )

);

$x->appendChild( $wthequote );
$wreference = $wdoc->createElement( "reference" );

$wreference->appendChild(

$wdoc->createTextNode( $myquote[ 'reference' ] )

);

$x->appendChild( $wreference );

$w->appendChild( $x );
}
$wdoc->save("../sidebar.xml");

hmsnacker123
04-17-2010, 06:19 PM
Um, to read XML you can use this function: http://www.php.net/simplexml_load_file

Very easy to use. Need any more help, let me know :)

I am Abby
04-18-2010, 12:17 AM
I'm reading and writing just fine...got the code here.

My problem is taking what I've read and adding to it before writing. My code is writing the new info but discarding the old, what it just read.

BLiZZaRD
04-18-2010, 12:37 AM
I am not a wizz at XML, and don't ever claim to be. but this line makes me wonder:



$wdoc = new DOMDocument();


If you are creating a new document every time, then technically there is nothing to append too. and since you are naming it the same:



$wdoc->save("../sidebar.xml");


The old one gets overwritten.

In the PHP fopen() there is an append code "+a" that opens reads writes at the end, preserving the old data. Perhaps XML has a similar function? Again, just my 2 cents. I will leave now.

I am Abby
04-19-2010, 02:05 AM
I don't believe my problem is in an append. If that were the case the second part would write...I'm only getting the first part to write to the xml.

traq
04-19-2010, 02:29 AM
I looked at DOMdocument functions a while ago, and they just don't seem to be organized intuitively. I far prefer simpleXML.

It looks to me like you're reading the xml into one object ($idoc), preparing the new data to be submitted, and then assigning it to a different object ($wdoc) to save it. So, I think Blizzard was right that you're overwriting the contents of the old xml file with only the new contents.

I am Abby
04-19-2010, 03:59 PM
even if saving idoc to wdoc before writing is wrong...

I don't see why the first thing I put in idoc is written but the second thing is not.

the info I get from the user is saved to the .xml
$sidebar = array();

$sidebar[] = array(

'id' => $insertcount,

'thequote' => $insertquote,

'reference' => $insertref

);

however the part I get from the .xml is not saved
//Read sidebar.xml and add to array

$isidebar = $idoc->getElementsByTagName( "myquote" );

foreach( $isidebar as $imyquote )

{

$iids = $imyquote->getElementsByTagName( "id" );

$iid = $iids->iten(0) ->nodeValue;

$ithequotes = $imyquote->getElementsByTagName( "thequote" );

$ithequote = $ithequotes->item(0) ->nodeValue;

$ireferences = $imyquote->getElementsByTagName( "reference" );

$ireference = $ireferences->item(0) ->nodeValue;

$sidebar[] = array(

'id' => $iid,

'thequote' => $ithequote,

'reference' => $ireference
 );
}

Because I put this stuff in the array last...if there was any problem at all...would it not have been the part that would save to the .xml?

traq
04-19-2010, 07:49 PM
//Read sidebar.xml and add to array

$isidebar = $idoc->getElementsByTagName( "myquote" );

foreach( $isidebar as $imyquote )

{

$iids = $imyquote->getElementsByTagName( "id" );

$iid = $iids->iten(0) ->nodeValue;

$ithequotes = $imyquote->getElementsByTagName( "thequote" );

$ithequote = $ithequotes->item(0) ->nodeValue;

$ireferences = $imyquote->getElementsByTagName( "reference" );

$ireference = $ireferences->item(0) ->nodeValue;

$sidebar[] = array(

'id' => $iid,

'thequote' => $ithequote,

'reference' => $ireference
 );
}

that's the part of your code that I'm not following at all -as I said, I don't like/use DOMdocument- so I couldn't say. It doesn't seem you would need to use all those variables to re-read/assign everything (in simpleXML, the xml is simply read into a multi-dimensional array, so it's ready to work with right away), but I wouldn't know for sure with DOMdocument.

I am Abby
04-20-2010, 01:59 PM
that's the part of your code that I'm not following at all -as I said, I don't like/use DOMdocument- so I couldn't say. It doesn't seem you would need to use all those variables to re-read/assign everything (in simpleXML, the xml is simply read into a multi-dimensional array, so it's ready to work with right away), but I wouldn't know for sure with DOMdocument.

This is what Codeexploiter showed us in the thread http://www.dynamicdrive.com/forums/showthread.php?t=14165
Reading and Writing XML

-----------------------------------------------------------

Ok so how would you read a xml...

<sidebar>
<myquote>
<id>1111</id>
<thequote>Hello World</thequote>

<reference>Abby Lee</reference>
</myquote>

</sidebar>


with simplexml and add info from your form...

$insertcount = $_POST["newcount"];

$insertquote = $_POST["iquote"];

$insertref = $_POST["iref"];

Maybe something like:

$idoc = simplexml_load_file('sidebar.xml');
// bring in elements from form to start building array
$sidebar = array();
$sidebar[] = array(
'id' => $insertcount,
'thequote' => $insertquote,
'reference' => $insertref
);
//run through .xml and add to array
foreach($idoc->children() as $myquotes)
{
foreach($myquotes->children() as $myquote)
{
$myquote
$sidebar = array(
//ok this is where I get lost...I need to put each of the elements of the array

I am Abby
04-20-2010, 07:07 PM
Did I loose everyone? Please help me.

I'm trying to go another way....

$idoc = simplexml_load_file('sidebar.xml');
foreach($idoc->children() as $myquotes)
{
foreach($myquotes->children() as $child)
{
foreach($child->children() as $kid)
{
echo "Name:".$kid->getName()."\n";
echo "Value:".$kid."\n";
echo "Attributes:".$kid->attributes()."\n\n";
}
}
}

I get nothing.
Now if I do an echo on $myquote in the first foreach I get "id", "thequote", and "reference" over and over.

traq
04-20-2010, 07:24 PM
something like this should work:

<?php

/**** NOT TESTED ****/

$insertcount = $_POST["newcount"];
$insertquote = $_POST["iquote"];
$insertref = $_POST["iref"];

$file = '../sidebar.xml';
$xml = simplexml_load_file($file);

/************************************************
I assume "newcount" is the id for the new entry?
is this submitted by the user?
if so, it could be better handled by PHP to avoid
duplicate ID's:

// find the last entry
// (assuming entries are all in numerical order,
// starting with # 1)
$last = count(xml->myquote);
// assign next entry number
$insertcount = $last + 1;
************************************************/

// this line assumes <sidebar> is your xml root
// add a new <myquote> entry
$newItem = $xml->addChild('myquote');

// add a new <id> to the new <myquote>
$newItem->addChild('id', $insertcount);
// add a new <thequote>
$newItem->addChild('thequote', $insertquote);
// add a new <reference>
$newItem->addChild('reference', $insertref);

// convert the $xml object to an xml string
// and save it to the sidebar.xml file
$xml = $xml->asXML($file);

?>

Basic reading of your xml file (also not tested, but I use this method often):



<?php

$file = '../sidebar.xml';
$xml = simplexml_load_file($file);

foreach($xml->children() as $myquote){
echo '
<hr>
id: '.$myquote->id.'<br>
the quote: '.$myquote->thequote.'<br>
reference: '.$myquote->reference;
}

/****************************************
if you wanted to list the entries in reverse order (e.g.,
most recent first), you could use this instead:

$i = count($xml->myquote)-1;
for($x=$i;$x>=0;$x--){
echo '
<hr>
id: '.$myquote[$x]->id.'<br>
the quote: '.$myquote[$x]->thequote.'<br>
reference: '.$myquote[$x]->reference;
}

// ! EDIT: fixed index references !

****************************************/

?>



//ok this is where I get lost...I need to put each of the elements of the array
No, you don't - I think that's where your confusion is. simplexml_load_file() already put everything into a simplexml object (not an array, but imagine it like an array). Nothing more to set up. You can just start using it, as in my example above.

I am Abby
04-20-2010, 07:54 PM
So your top bit of code there gets the form elements and adds it to the existing xml? If so, I didn't think you could do that...I thought you had to read, add to, write?

traq
04-20-2010, 07:58 PM
simplexml_load_file() reads the existing xml file and turns it into a simplexml object (which is ready for us to manipulate).

the ->addChild() statements add the new info (in this case, your $_POST info) to the simplexml object.

->asXML() converts the simplexml object into an xml string (and writes it to file, too, if a file path is included).

I am Abby
04-21-2010, 04:36 PM
Wow!

You guys were so right...this is so much easier than creating a DOMDocument.

I am Abby
04-21-2010, 04:47 PM
Is there an easy way to delete an entry?

traq
04-21-2010, 07:58 PM
there's no simplexml function, but you can use unset():
<?php

$xml = simplexml_load_file('file.xml');
unset($xml->node->to_delete);
$xml = $xml->asXML;

?>Include any applicable indices, or you may end up losing ALL nodes that match the path you enter.

I am Abby
04-21-2010, 08:21 PM
So, all I would have to do is run everything through a foreach...find the one I don't like and unset() it.

Thanks.