@EDF
Век живи - век учись! Банально, но факт...

Как правильно написать рекурсивную функцию для создания дерева меню из многомерного ассоциативного массива?

Здравствуйте.

Дано: XML файл.
Необходимо: обрабатывать XML-файл и выводить HTML на его основе.
Структура XML-файла начинается с <params>, в него вложен <systems>. Дальше идут группы <group>, которые могут иметь любое число вложений. И последним уровнем идет <parameter> c <value> внутри.
То есть отличия только во вложенности тегов <group>. И вот эти группы и должны выводиться в виде элементов меню. Текст должен браться из атрибута textid тега <group>.

Вариант с одним уровнем я поначалу сделал, но, увы, группы могут иметь неизвестное число уровней вложений и мое решение вообще не подошло.

Я перевожу XML в массив и уже из него пытаюсь строить дерево.
Честно говоря, я чайник и плаваю пока в элементарных вещах. И если работу с массивом еще как-то можно было осилить, то в купе с рекурсивной функцией я застрял намертво.

На данный момент имеется одно из неверных решений. Дерево выводится без уровней вложения и не по порядку.

Может кто-то поможет переписать мою функцию (в процедурном стиле), чтобы выводилось корректное дерево?

Пример своего "кода" положил в один файл для удобства:
$string = <<<XML
<?xml version="1.0" encoding="UTF-8"?>
<system>
	<params>
		<group id="a08150" txtid="Item A Level 1">
			<parameter id="a08151" type="1" txtid="A Parameter 1-1">
				<value>true</value>
			</parameter>
			<parameter id="a08152" type="1" txtid="A Parameter 1-2">
				<value>false</value>
			</parameter>
			<parameter id="a08153" type="3" txtid="A Parameter 1-3">
				<value>1100</value>
			</parameter>
			<parameter id="a08154" type="0" txtid="A Parameter 1-4">
				<value>Text</value>
			</parameter>
		</group>

		<group id="a08200" txtid="Item B Level 1">
			<group id="a08210" txtid="Subitem B Level 2">
				<group id="a08220" txtid="Subitem B Level 3">
					<parameter id="a08221" type="0" txtid="B Parameter 3-1">
						<value>Example Text</value>
					</parameter>
				</group>
			</group>
		</group>

		<group id="a08300" txtid="Item C Level 1">
			<group id="a08310" txtid="Subitem C Level 2">
				<group id="a08320" txtid="Subitem C Level 3-1">
					<parameter id="a08321" type="0" txtid="C Parameter 3-1-1">
						<value>Example Text</value>
					</parameter>
					<parameter id="a08322" type="0" txtid="C Parameter 3-1-2">
						<value>Example Text</value>
					</parameter>
					<parameter id="a08322" type="0" txtid="C Parameter 3-1-3">
						<value>Example Text</value>
					</parameter>
				</group>

				<group id="a08330" txtid="Subitem C Level 3-2">
					<group id="a08340" txtid="Subitem C Level 4-1">
						<group id="a08350" txtid="Subitem C Level 5-1">
							<parameter id="a08331" type="0" txtid="C Parameter 5-1">
								<value>Example Text</value>
							</parameter>
							<parameter id="a08332" type="0" txtid="C Parameter 5-2">
								<value>Example Text</value>
							</parameter>
							<parameter id="a08332" type="0" txtid="C Parameter 5-3">
								<value>Example Text</value>
							</parameter>
						</group>
					</group>
				</group>

				<parameter id="a08311" type="0" txtid="C Parameter 2-1">
					<value>Example Text</value>
				</parameter>
			</group>
			<parameter id="a08301" type="0" txtid="C Parameter 1-1">
				<value>Example Text</value>
			</parameter>
			<parameter id="a08302" type="0" txtid="C Parameter 1-2">
				<value>Example Text</value>
			</parameter>
		</group>

		<group id="a08160" txtid="Item D Level 1">
			<parameter id="a08161" type="0" txtid="Text Input">
				<value>Example Text</value>
			</parameter>
			<parameter id="a08162" type="1" txtid="Checkbox (Boolean) unchecked">
				<value>false</value>
			</parameter>
			<parameter id="a08163" type="1" txtid="Checkbox (Boolean) checked">
				<value>true</value>
			</parameter>
			<parameter id="a08164" type="2" txtid="Float">
				<value>25.75</value>
			</parameter>
			<parameter id="a08165" type="3" txtid="Integer">
				<value>1979</value>
			</parameter>
			<parameter id="a08166" type="4" txtid="IP4">
				<value>127.0.0.1</value>
			</parameter>
			<parameter id="a08167" type="5" txtid="IP6">
				<value>0:0:0:0:0:ffff:7f00:1</value>
			</parameter>
			<parameter id="a08168" type="7" txtid="List">
				<value>3</value>
				<range>
					<row txtid="List1">1</row>
					<row txtid="List2">2</row>
					<row txtid="List3">3</row>
					<row txtid="List4">4</row>
					<row txtid="List5">5</row>
				</range>
			</parameter>
		</group>
	</params>
</system>
XML;

	$xml         = simplexml_load_string( $string );
	$json_string = json_encode( $xml );
	$input_array = json_decode( $json_string, TRUE );


	function build_tree( $input_array, $tree = '' )
	{
		if( !is_array( $input_array ) )
		{
			return '';
		}

		foreach( $input_array as $key => $value )
		{
			if( $key === 'group' )
			{
				$branch = '';

				if( isset( $value[ '@attributes' ][ 'txtid' ] ) )
				{
					$title = $value[ '@attributes' ][ 'txtid' ];

					if( $title )
					{
						$branch .= '<li>' . $title . '</li>';
					}
				}
				else
				{
					foreach( $value as $inner_values )
					{
						$title = '';

						if( isset( $inner_values[ '@attributes' ] ) )
						{
							$title = $inner_values[ '@attributes' ][ 'txtid' ];
						}

						if( $title )
						{
							$branch .= '<li>' . $title . '</li>';
						}
					}
				}

				if( $branch )
				{
					$tree .= '<ul>' . $branch . '</ul>';
				}
			}

			$tree .= build_tree( $value );
		}

		return $tree;
	}


	echo build_tree( $input_array );
  • Вопрос задан
  • 803 просмотра
Решения вопроса 1
@EDF Автор вопроса
Век живи - век учись! Банально, но факт...
Отвечу сам, может пригодится кому. Итоговое решение получилось примерно таким:
function build_tree( $input_array, $output = '' )
{
	if( !is_array( $input_array ) )
	{
		return '';
	}

	if( array_key_exists( 'group', $input_array ) )
	{
		$output .= '<ul>';
	}

	foreach( $input_array as $key => $value )
	{
		if( ( isset( $value[ '@attributes' ][ 'txtid' ] ) ) && ( $key !== 'parameter' ) )
		{
			$id    = $value[ '@attributes' ][ 'id' ];
			$title = $value[ '@attributes' ][ 'txtid' ];

			$output .= '<li>' . $title;

			if( array_key_exists( 'group', $value ) )
			{
				$output .= build_tree( $value );
			}

			$output .= '</li>';
		}
		elseif( $key !== 'parameter' )
		{
			$output .= build_tree( $value );
		}
	}

	if( array_key_exists( 'group', $input_array ) )
	{
		$output .= '</ul>';
	}

	return $output;
}
Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 1
AnnTHony
@AnnTHony
Интроверт
С php не работал, но возможна данная статья прольет свет истины.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы