XML DOM *brain explodes*

PHP programming forum. Ask questions or help people concerning PHP code. Don't understand a function? Need help implementing a class? Don't understand a class? Here is where to ask. Remember to do your homework!

Moderator: General Moderators

Post Reply
AlexC
Forum Commoner
Posts: 83
Joined: Mon May 22, 2006 10:03 am

XML DOM *brain explodes*

Post by AlexC »

Hey there,

I'm been trying for the past few hours to edit an XML file using DomDocument - however it's becoming very hard!

I have the following XML file:

Code: Select all


<?xml version="1.0"?>
<controllers>

	<controller id="195" for_sector="S1">		
		<mod>menu</mod>
		<con>index</con>
		<sec>index</sec>
		<config>
			<display_category>21</display_category>
			<wrap_controller>false</wrap_controller>
			<display_title>false</display_title>
		</config>	
	</controller>
	
	<controller id="243" for_sector="S2">			
		<mod>page</mod>
		<con>index</con>
		<sec>index</sec>
		<config>
			<wrap_controller>true</wrap_controller>
			<display_title>true</display_title>
			<display_page>2</display_page>
		</config>
	</controller>	
	
	<controller id="254" for_sector="S2">			
		<mod>session</mod>
		<con>index</con>
		<sec>index</sec>
		<config>
			<wrap_controller>true</wrap_controller>
			<display_title>true</display_title>
		</config>
	</controller>	
	
	<controller id="185" for_sector="S2">
		<mod>poll</mod>
		<con>index</con>
		<sec>index</sec>
		<config>
			<wrap_controller>true</wrap_controller>
			<display_title>true</display_title>
		</config>
	</controller>
	
	<controller id="342" for_sector="S2">
		<mod>article</mod>
		<con>headlines</con>
		<sec>index</sec>
		<config>
			<wrap_controller>true</wrap_controller>
			<display_title>true</display_title>
		</config>
	</controller>
	
</controllers>
which I am trying to edit with:

Code: Select all

//---
		// edit_module() edits a module that is set in the XML file [Thanks rza on ##php!]
		// @param int $controller_id
		// @param array $details
		// @return bool		
		//---
		public function edit_module( $controller_id, $details ) {
			#Zula::debug_print( $details );		
			#$details['con'] = 'foo';
			if ( !$this->controller_exists( $controller_id ) ) {
				// oops!
				Error::report( 'Theme layout could not edit controller', 'controllerID "'.$controller_id.'" does not exist', Error::_WARNING );
				return false;
			}
			// Create the new nodes for each of the details
			$this->new_nodes = array();
			foreach( $details as $key=>$val ) {
				if ( is_array( $val ) ) {
					foreach( $val as $config_key=>$config_val ) {
						$this->new_nodes['config'][ $config_key ] = $this->sector_map->createElement( $config_key, $config_val );
					}
				} else {
					$this->new_nodes[ $key ] = $this->sector_map->createElement( $key, $val );
				}						
			}
			// Time for the fun, brain exploding part
			$controller_nodes = $this->sector_map->getElementsByTagName( 'controller' );
			foreach( $controller_nodes as $node ) {
				if ( $node->getAttribute( 'id' ) != $controller_id ) {
					continue;
				}
				// This is the one we'll be editing!
				$children = $node->childNodes;
				for( $i=0; $i < $children->length; $i++ ) {				 
					if ( $children->item( $i )->nodeName != 'config' && isset( $this->new_nodes[ $children->item( $i )->nodeName ] ) ) {						
						$node->replaceChild( $this->new_nodes[ $children->item( $i )->nodeName ], $children->item( $i ) );						
					}
				}				
			}
			$this->save_sector_map();
			return true;
		}
here is what $details array is in the format of:

Code: Select all

array
(
    [mod] => menu
    [con] => index
    [sec] => index
    [config] => Array
        (
            [display_category] => 22
            [display_title] => true
            [force_title] => 
        )

)
Basically, I need to edit the correct controller element and either replace the value with the new one (in $details) if it exists, or create the element if it does not exist - but my brain has exploded and I really can not do it =(

Could someone please help? I'd be very very happy if you do :D
User avatar
volka
DevNet Evangelist
Posts: 8391
Joined: Tue May 07, 2002 9:48 am
Location: Berlin, ger

Post by volka »

Have you thought about using xpath?

Code: Select all

<?php
$testdoc = new DOMDocument;
$testdoc->preserveWhiteSpace = false;
$testdoc->formatOutput = true;
$testdoc->loadxml('<controllers>
	<controller id="195" for_sector="S1">      
		<mod>menu</mod>
	</controller>
	<controller id="243" for_sector="S2">         
		<mod>page</mod>
	</controller>   
	<controller id="254" for_sector="S2">         
		<mod>session</mod>
	</controller>   
	<controller id="185" for_sector="S2">
		<mod>poll</mod>
	</controller>
	<controller id="342" for_sector="S2">
		<mod>article</mod>
	</controller>
</controllers>');
$xpath = new DOMXPath($testdoc);

$controller_id = 243;
$ns = $xpath->query('//controller[@id='.$controller_id.']');
echo $controller_id, ' ', $ns->length, "<br />\n";

$controller_id = 244;
$ns = $xpath->query('//controller[@id='.$controller_id.']');
echo $controller_id, ' ', $ns->length, "<br />\n";
AlexC
Forum Commoner
Posts: 83
Joined: Mon May 22, 2006 10:03 am

Post by AlexC »

Volka, xpath can not write back to the XML DOM though, can it?
User avatar
volka
DevNet Evangelist
Posts: 8391
Joined: Tue May 07, 2002 9:48 am
Location: Berlin, ger

Post by volka »

XPath is for selecting nodes, not modifying them. But it returns "normal" DOMNode objects that you can manipulate like any other DOMNode.
e.g.

Code: Select all

<?php
$dom = DOMDocument::loadxml('<r>
	<a>abc</a>
	<a>def</a>
	<a>ghi</a>
</r>');
$xpath = new DOMXpath($dom);
$ns = $xpath->query('//a[position()=2]');
if ( 0<$ns->length ) {
	$a = $ns->item(0);
	while( null!=$a->firstChild ) {
		$a->removeChild($a->firstChild);
	}
	$a->appendChild($dom->createElement('b', 'foo'));
}

echo $dom->savexml();
prints

Code: Select all

<?xml version="1.0"?>
<r>
	<a>abc</a>
	<a><b>foo</b></a>
	<a>ghi</a>
</r>
Post Reply