I'm lost with the DOM - how do I change one node attribute?

Author Message

Pascal Specht

Monday 10 September 2007 7:47:32 am

Hi,

can someone help me understand what I'm doing wrong? I'm using a text attribute (data_text_1) in an order. This text attribute contains a serialized dom tree like:

<?xml version="1.0" encoding="UTF-8"?>
<shop_account>
<salutation>1</salutation>
<first-name>Pascal</first-name>
<last-name>Specht</last-name>
...
<transaction>[no transaction]</transaction>
</shop_account>

and I'd like to change the content "[no transaction]" to "[test]"...

I thought that I could do that by unserializing, then grabbing the element with elementsByName, and applying setAttribute and writing back as a string, but it doesn't... The node still contains [no transaction]!

				$xml = new eZXML();
				$xmlDoc =& $order->attribute( 'data_text_1' );
				if( $xmlDoc != null )
				{
					$dom =& $xml->domTree( $xmlDoc );
					if ($dom) 
					{
						$item =& $dom->elementsByName( "transaction" );
						$item->setAttribute( 'data_text', "[test]" );
					}
				}
				$order->setAttribute( 'data_text_1', $xmlDoc->toString() );

Obviously this doesn't work. Any ideas how to correct the problem would be greatly appreciated!

Pascal

Pascal von Büren

Monday 10 September 2007 8:55:42 am

Hi Pascal,

your code ends quite quickly, did you call

$order->store();

afterwards?

Pascal Specht

Tuesday 11 September 2007 2:27:29 am

Hi Pascal,

I must admit I hadn't the order->store() instruction, but unfortunately, after adding it (and clearing the cache) it doesn't get better, the order still is unchanged. I suppose the two $item-> instructions to be wrong...

Thanks for your help,
Pascal

Pascal von Büren

Tuesday 11 September 2007 3:15:19 am

Ok, i can see two more possilbe problems.

First of all, <b>elementsByName</b> returns an Array. So you could look over the result or use <b>elementByName</b>.

Additionally, you want to set the TextContent of a Node, but you use setAttribute. You'd be off better using <b>setContent</b>.

One more question: How are you calling this script? By CLI or as HTTP request?

André R.

Tuesday 11 September 2007 3:43:56 am

Something like this maybe?

        $items =& $dom->elementsByName( "transaction" );
        
        // Note: php4 foreach copy's array values instead of referencing them
        for( $i = 0, $c = count( $items ); $c > $i ; $i++)
        {
            $items[$i]->setContent("[test]");
            //$items[$i]->setAttribute( 'data_text', "[test]" ); this will result in <transaction data_text="[test]">[no transaction]</transaction>
        }

eZ Online Editor 5: http://projects.ez.no/ezoe || eZJSCore (Ajax): http://projects.ez.no/ezjscore || eZ Publish EE http://ez.no/eZPublish/eZ-Publish-Enterprise-Subscription
@: http://twitter.com/andrerom

Pascal Specht

Tuesday 11 September 2007 5:39:15 am

I built in both of your suggestions, and I have now this code, which apparently does not raise any warnings or errors. The thing is that the setContent("[test]") now gets called but when I look at my data_text_1, it still contains the original XML + the two ## on each side...

				$xml = new eZXML();
				$xmlDoc =& $order->attribute( 'data_text_1' );

				if( $xmlDoc != null )
				{
					$dom =& $xml->domTree( $xmlDoc );
					if ($dom) 
					{
						$items =& $dom->elementsByName( "transaction" );
						for( $i = 0, $c = count( $items ); $c > $i ; $i++)
						{
							$items[$i]->setContent("[test]");
							$items[$i]->store();    
						}
					}
				}
				$str = "##" . $dom->toString() . "##";
				$order->setAttribute( 'data_text_1', $str );
				$order->store();

Originally, what I wanted to do is simply add one item into a string based XML text...

Any help much appreciated!

Pascal von Büren

Tuesday 11 September 2007 7:24:54 am

Hi Pascal,
one more try:

                                $xml = new eZXML();
                                $xmlDoc =& $order->attribute( 'data_text_1' );
 
                                if( $xmlDoc != null )
                                {
                                        $dom =& $xml->domTree( $xmlDoc );
                                        if ($dom) 
                                        {
                                                $root =& $dom->root(); 
                                                $items =& $root->elementsByName( "transaction" );
                                                for( $i = 0, $c = count( $items ); $c > $i ; $i++)
                                                {
                                                        $items[$i]->setContent("[test]");
                                                }
                                        }
                                }
                                $str = "##" . $dom->toString() . "##";
                                $order->setAttribute( 'data_text_1', $str );
                                $order->store();

(getting the elements starting from DOM-Root)

Pascal Specht

Tuesday 11 September 2007 8:24:59 am

Hi,

This really drives me crazy! I spent the whole day on it, and it still doesn't work...
Obviously the code changes the node content, but the final result doesn't reflect the change!

				$xml = new eZXML();
				$xmlDoc = "<?xml version=\"1.0\" encoding=\"UTF-8\"?> <a> <xxx>*</xxx> </a>";

				if( $xmlDoc != null )
				{
					$dom =& $xml->domTree( $xmlDoc );
					if ($dom) 
					{
						$root =& $dom->root(); 

                         $items =& $root->elementsByName( "xxx" );						
						for( $i = 0, $c = count( $items ); $c > $i ; $i++)
						{
							$items[$i]->setContent("**********");
							echo "!item change occured!";
						}
					} 
				}

				echo "<hr><pre>";
				echo htmlspecialchars( $xmlDoc );
				echo "<hr>";
				echo htmlspecialchars( $dom->toString() );
				echo "<hr></pre>";

produces the following output:

!item change occured!
--------------------------------------------------------------------------------------------------------------------------------
<?xml version="1.0" encoding="UTF-8"?> 
<a> 
  <xxx>*</xxx> 
</a>
--------------------------------------------------------------------------------------------------------------------------------
<?xml version="1.0" encoding="UTF-8"?>
<a>
  <xxx>*</xxx>
</a>
--------------------------------------------------------------------------------------------------------------------------------

Pascal Specht

Tuesday 11 September 2007 9:18:33 am

OK, so for anyone interrested in doing it, I found the solution now:

To replace all occurences of <xxx>*</xxx> you can do:

				$xml = new eZXML();
				$xmlDoc = "<?xml version=\"1.0\" encoding=\"UTF-8\"?> <a> <xxx>*</xxx> </a>";

				if( $xmlDoc != null )
				{
					$dom =& $xml->domTree( $xmlDoc );

					if ($dom) 
					{
						$root =& $dom->root(); 

                        $items =& $root->elementsByName( "xxx" );						
						for( $i = 0, $c = count( $items ); $c > $i ; $i++)
						{
							$element = $items[$i];
							if ( count( $element->Children ) > 0 )
							{
								 foreach( array_keys( $element->Children ) as $key )
								 {
									 $child =& $element->Children[$key];
									 $child->setContent("**********");
								 }
							}
						}
					}
				}

Powered by eZ Publish™ CMS Open Source Web Content Management. Copyright © 1999-2014 eZ Systems AS (except where otherwise noted). All rights reserved.