Simplexml

I’m making a few yii extension that may use xml input, just gauging interest and seeing if it would be useful to the community.

For those interested: http://us.php.net/simplexml

SimpleXML is a very easy way to parse xml.

FYI

I ran into an issue with simpleXML where it does not properly encode a "&" or a "%". so if you do a $foo->addChild("bar", "50% off"); it blows up badly like:.



Warning: SimpleXMLElement::addChild() [simplexmlelement.addchild]: unterminated entity reference  


To fix you need to CData the element's data yourself.

Just thought I would give you a heads up on this…

nz

Yea, I’ve read about this but I forgot. Thanks  :D

I think it's pretty safe to rely on SimpleXML. Most people have it since it's enabled by default in >= PHP 5. You have to use --disable-simplexml when compiling PHP if you want to turn it off.

Hi

I use SimpleXML all the time.

I’m new to Yii & frameworks and am about to convert my portfolio website to Yii.

I have a lot of XML files that need to be parsed…

Not quite sure what approach to use…

Any plans for an extension, or advice for the right approach?

thanks in advance.

Here are some functions I wrote that use SimpleXML. Thought I’d share.




	/**

	* Converts an array to Xml

	*

	* @param mixed $arData The array to convert

	* @param mixed $sRootNodeName The name of the root node in the returned Xml

	* @param string $sXml The converted Xml

	*/

	public function arrayToXml( $arData, $sRootNodeName = 'data', $sXml = null )

	{

		// turn off compatibility mode as simple xml doesn't like it

		if ( 1 == ini_get( 'zend.ze1_compatibility_mode' ) )

			ini_set( 'zend.ze1_compatibility_mode', 0 );


		if ( null == $sXml )

			$sXml = simplexml_load_string( "<?xml version='1.0' encoding='utf-8'?><{$sRootNodeName} />" );


		// loop through the data passed in.

		foreach ( $arData as $_sKey => $_oValue )

		{

			// no numeric keys in our xml please!

			if ( is_numeric($_sKey ) )

				$_sKey = "unknownNode_". ( string )$_sKey;


			// replace anything not alpha numeric

			$_sKey = preg_replace( '/[^a-z]/i', '', $_sKey );


			// if there is another array found recrusively call this function

			if ( is_array( $_oValue ) )

			{

				$_oNode = $sXml->addChild( $_sKey );

				self::arrayToXml( $_oValue, $sRootNodeName, $_oNode );

			}

			else

			{

				// add single node.

				$_oValue = htmlentities( $_oValue );

				$sXml->addChild( $_sKey, $_oValue );

			}

		}


		return( $sXml->asXML() );

	}

	



and this method converts an array of CActiveRecord’s to an XML string. Will also convert an array to a string suitable for use with jqGrid AJAX calls:




	/**

	* Returns an Xml string representation of an array of CActiveRecords

	*

	* @param array $oRS

	* @param array $arOptions

	*/

	public function asXml( $arData, $arOptions = null )

	{

		//	Initialize...

		$_sHeader = '';

		$_sOut = '';

		$_oSchema = null;


		//	Process options...

		$_bjqGrid = self::getOption( $arOptions, 'jqGrid', false );


		//	Default options for jqGrid

		if ( $_bjqGrid )

		{

			$_sContainer = 'row';

			$_sElement = 'cell';

			$_bUseColumnElementNames = false;

			$_bIdInAttribute = true;

			$_sIdName = 'id';

			$_bUseCDataForStrings = true;

			$_bEncloseResults = true;

			$_sEncloseTag = 'rows';

			$_arAddElements = self::getOption( $arOptions, 'addElements', null );

			$_bAddTypes = false;

		}

		else

		{

			$_sContainer = self::getOption( $arOptions, 'container', 'row' );

			$_sElement = self::getOption( $arOptions, 'element', 'cell' );

			$_bUseColumnElementNames = self::getOption( $arOptions, 'useColumnElementNames', false );

			$_bIdInAttribute = self::getOption( $arOptions, 'idInAttribute', true );

			$_bUseCDataForStrings = self::getOption( $arOptions, 'useCDataForStrings', true );

			$_bEncloseResults = self::getOption( $arOptions, 'encloseResults', false );

			$_sEncloseTag = self::getOption( $arOptions, 'encloseTag', 'rows' );

			$_bAddTypes = self::getOption( $arOptions, 'addTypes', false );

			$_sAddTypeAttributeName = self::getOption( $arOptions, 'addTypeAttributeName', 'type' );

		}


		$_sIdName = self::getOption( $arOptions, 'idName', 'id' );

		$_arColList = self::getOption( $arOptions, 'columnList', null );

		$_bAllowNulls = self::getOption( $arOptions, 'allowNulls', false );

		$_sReplaceNullWith = self::getOption( $arOptions, 'replaceNullWith', '&nbsp;' );

		$_arInnerElements = self::getOption( $arOptions, 'innerElements', null );

		$_arAddElements = self::getOption( $arOptions, 'addElements', null );

		$_arIgnoreColumns = self::getOption( $arOptions, 'ignoreColumns', null );


		$_sPrimaryKey = '';


		//	Loop through array of ActiveRecords

		foreach ( $arData as $_oRow )

		{

			//	Get the Pk

			if ( $_bIdInAttribute && $_bUseColumnElementNames && $_sPrimaryKey == '' )

			{

				$_sIdName = $_oRow->tableSchema->primaryKey;

				$_sPrimaryKey = $_oRow->getPrimaryKey();

			}


			$_sOut .= CHtml::openTag( $_sContainer, $_bIdInAttribute ? array( $_sIdName => $_oRow->primaryKey ) : array() );


			$_arAttr = $_oRow->getAttributes( null );


			foreach ( $_arAttr as $_sKey => $_oValue )

			{

				if ( is_array( $_arIgnoreColumns ) && in_array( $_sKey, $_arIgnoreColumns ) )

					continue;


				$_sElemToUse = ( $_bUseColumnElementNames ) ? $_sKey : $_sElement;

				$_sType = gettype( $_oValue );

				$_sOut .= CHtml::tag( $_sElemToUse, ( $_bAddTypes ? array( 'type' => $_sType ) : array() ), ( $_sType == 'string' && $_bUseCDataForStrings ) ? CHtml::cdata( $_oValue ) : $_oValue );

			}


			//	Anything extra to add?

			if ( $_arAddElements && is_array( $_arAddElements ) )

			{

				foreach ( $_arAddElements as $_oElement )

				{

					if ( $_oElement[ 'type' ] == 'function' )

					{

						$_sResult = $_oRow->{$_oElement['value']}( $_oRow );

						$_sOut .= CHtml::tag( $_oElement[ 'name' ], ( $_bAddTypes ? array( 'type' => $_oElement[ 'type' ] ) : array() ), ( $_bUseCDataForStrings  ) ? CHtml::cdata( $_sResult ) : $_sResult );

					}

					else

					{

						if ( $_oElement[ 'value' ] == '**rowdata**' )

						{

							try

							{

								$_sTemp = 'return( $_oRow->' . $_oElement[ 'column' ] . ');';

								$_oResult = eval( $_sTemp );

								$_sOut .= CHtml::tag( $_oElement[ 'name' ], ( $_bAddTypes ? array( 'type' => $_oElement[ 'type' ] ) : array() ), ( $_oElement[ 'type' ] == 'string' && $_bUseCDataForStrings ) ? CHtml::cdata( $_oResult ) : $_oResult );

							}

							catch ( Exception $_ex )

							{

								//	Ignore...

								$_sOut .= CHtml::tag( $_oElement[ 'name' ], ( $_bAddTypes ? array( 'type' => $_oElement[ 'type' ] ) : array() ), '' );

							}

						}

						else

							$_sOut .= CHtml::tag( $_oElement[ 'name' ], ( $_bAddTypes ? array( 'type' => $_oElement[ 'type' ] ) : array() ), ( $_oElement[ 'type' ] == 'string' && $_bUseCDataForStrings ) ? CHtml::cdata( $_oElement[ 'value' ] ) : $_oElement[ 'value' ] );

					}

				}

			}


			$_sOut .= CHtml::closeTag( $_sContainer );

		}


		//	Anything extra to add?

		if ( $_arInnerElements && is_array( $_arInnerElements ) )

		{

			foreach ( $_arInnerElements as $_oElement )

				$_sHeader .= CHtml::tag( $_oElement[ 'name' ], ( $_bAddTypes ? array( 'type' => $_oElement[ 'type' ] ) : array() ), ( $_oElement[ 'type' ] == 'string' && $_bUseCDataForStrings ) ? CHtml::cdata( $_oElement[ 'value' ] ) : $_oElement[ 'value' ] );

		}


		if ( $_bEncloseResults && ! empty( $_sEncloseTag ) )

			$_sOut = CHtml::tag( $_sEncloseTag, array( 'itemCount' => sizeof( $arData ) ), $_sHeader . $_sOut );


		//	And return...

		return( $_sOut );

	}




<SHAMELESS_PLUG>

[b]These methods are part of the CPSHelp object in my [url=&quot;http://code.google.com/p/ps-yii-extensions/&quot;]extension library[/url].[/b]

</SHAMELESS_PLUG>