플랫 데이터에서 PHP에서 계층 적 HTML 태그를 구축하십시오
문제
PHP에서 데이터가 포함 된 계층 적 태그 세트를 어떻게 구축합니까?
예를 들어 중첩 목록 :
<div>
<ul>
<li>foo
</li>
<li>bar
<ul>
<li>sub-bar
</li>
</ul>
</li>
</ul>
</div>
이것은 다음과 같은 플랫 데이터에서 빌드됩니다.
nested_array = array();
nested_array[0] = array('name' => 'foo', 'depth' => 0)
nested_array[1] = array('name' => 'bar', 'depth' => 0)
nested_array[2] = array('name' => 'sub-bar', 'depth' => 1)
예와 같이 멋지게 형식화되어 있다면 좋을 것입니다.
해결책
편집 : 추가 서식
의견에서 이미 말했듯이 데이터 구조는 다소 이상합니다. OIS와 같은 텍스트 조작을 사용하는 대신 DOM을 선호합니다.
<?php
$nested_array = array();
$nested_array[] = array('name' => 'foo', 'depth' => 0);
$nested_array[] = array('name' => 'bar', 'depth' => 0);
$nested_array[] = array('name' => 'sub-bar', 'depth' => 1);
$nested_array[] = array('name' => 'sub-sub-bar', 'depth' => 2);
$nested_array[] = array('name' => 'sub-bar2', 'depth' => 1);
$nested_array[] = array('name' => 'sub-sub-bar3', 'depth' => 3);
$nested_array[] = array('name' => 'sub-sub3', 'depth' => 2);
$nested_array[] = array('name' => 'baz', 'depth' => 0);
$doc = new DOMDocument('1.0', 'iso-8859-1');
$doc->formatOutput = true;
$rootNode = $doc->createElement('div');
$doc->appendChild($rootNode);
$rootList = $doc->createElement('ul');
$rootNode->appendChild($rootList);
$listStack = array($rootList); // Stack of created XML list elements
$depth = 0; // Current depth
foreach ($nested_array as $nael) {
while ($depth < $nael['depth']) {
// New list element
if ($listStack[$depth]->lastChild == null) {
// More than one level at once
$li = $doc->createElement('li');
$listStack[$depth]->appendChild($li);
}
$listEl = $doc->createElement('ul');
$listStack[$depth]->lastChild->appendChild($listEl);
array_push($listStack, $listEl);
$depth++;
}
while ($depth > $nael['depth']) {
array_pop($listStack);
$depth--;
}
// Add the element itself
$li = $doc->createElement('li');
$li->appendChild($doc->createTextNode($nael['name']));
$listStack[$depth]->appendChild($li);
}
echo $doc->saveXML();
서식 규칙은 이상합니다. 마지막 줄을 다음으로 바꾸려면 다음을 달성하십시오.
printEl($rootNode);
function printEl(DOMElement $el, $depth = 0) {
$leftFiller = str_repeat("\t", $depth);
$name = preg_replace('/[^a-zA-Z]/', '', $el->tagName);
if ($el->childNodes->length == 0) {
// Empty node
echo $leftFiller . '<' . $name . "/>\n";
} else {
echo $leftFiller . '<' . $name . ">";
$printedNL = false;
for ($i = 0;$i < $el->childNodes->length;$i++) {
$c = $el->childNodes->item($i);
if ($c instanceof DOMText) {
echo htmlspecialchars($c->wholeText);
} elseif ($c instanceof DOMElement) {
if (!$printedNL) {
$printedNL = true;
echo "\n";
}
printEl($c, $depth+1);
}
}
if (!$printedNL) {
$printedNL = true;
echo "\n";
}
echo $leftFiller . '</' . $name . ">\n";
}
}
다른 팁
의견 필드에 너무 정교한 질문에 대해 질문이 있습니다.
속성 데이터를 어떻게 맞추고 싶습니까? Whory 테이블이 필요합니다
array('html', null, array (
array( 'div' , null , array(
array('ul', array('id'=>'foo'), array(
array('li', null, 'foo' ),
array('li', null, array(
array(null,null, 'bar'),
array('ul', null, array(
array('li', null, 'sub-bar' )
))
))
))
))
))
));
이는 프로그래밍 방식으로 HTML 데이터 세트를 정확하게 표현하는 데 필요한 최소 구조이기 때문입니다.
나는 "텍스트-노드"요소의 필요성을 제거하여 약간의 속임수를 보냈습니다.
배열 (이름, 속성, 어린이)
'children'에 대한 배열 대신 문자열이 있고 암시 적 텍스트-노드가 있으며 이름 == null이있는 노드에는 태그가 없으므로 텍스트 노드입니다.
내가 원한다고 생각하는 것은 적절한 프로그래밍 방식 DOM 생성 도구로, 기존의 HTML을 나무에 구문 분석하여 인생을 더 편하게 만들 수 있습니다.
FWIW, 위의 구조는 HTML로 쉽게 직렬화 될 수 있습니다.
function tohtml( $domtree ){
if( is_null($domtree[0]) ){
if( !is_array($domtree[2])){
return htmlentities($domtree[2]);
}
die("text node cant have children!");
}
$html = "<" . $domtree[0];
if( !is_null( $domtree[1] ) )
{
foreach( $domtree[1] as $name=>$value ){
$html .= " " . $name . '="' . htmlentities($value) . '"';
}
}
$html .= ">" ;
if( !is_null($domtree[2]) ){
if( is_array($dometree[2]) ){
foreach( $domtree[2] as $id => $item ){
$html .= tohtml( $item ); # RECURSION
}
}
else {
$html .= htmlentities($domtree[2]);
}
}
$html .= "</" . $domtree[1] . ">";
return $html;
}
당신은 같은 것을 의미합니다
function array_to_list(array $array, $width = 3, $type = 'ul', $separator = ' ', $depth = 0)
{
$ulSpace = str_repeat($separator, $width * $depth++);
$liSpace = str_repeat($separator, $width * $depth++);
$subSpace = str_repeat($separator, $width * $depth);
foreach ($array as $key=>$value) {
if (is_array($value)) {
$output[(isset($prev) ? $prev : $key)] .= "\n" . array_to_list($value, $width, $type, $separator, $depth);
} else {
$output[$key] = $value;
$prev = $key;
}
}
return "$ulSpace<$type>\n$liSpace<li>\n$subSpace" . implode("\n$liSpace</li>\n$liSpace<li>\n$subSpace", $output) . "\n$liSpace</li>\n$ulSpace</$type>";
}
echo array_to_list(array('gg', 'dsf', array(array('uhu'), 'df', array('sdf')), 'sdfsd', 'sdfd')) . "\n";
생산합니다
<ul>
<li>
gg
</li>
<li>
dsf
<ul>
<li>
<ul>
<li>
uhu
</li>
</ul>
</li>
<li>
df
<ul>
<li>
sdf
</li>
</ul>
</li>
</ul>
</li>
<li>
sdfsd
</li>
<li>
sdfd
</li>
</ul>
하위 목록이 설명으로 시작되지 않으면 약간의 간격이 있다는 것을 알고 있습니다.
개인적으로 나는 일반적으로 HTML이 PHP에서 작업하기 쉬운만큼 어떻게 보이는지에 관심이 없습니다.
편집 : 알겠습니다. 먼저이 작업을 통해 실행하면 작동합니다 ... : P
function flat_array_to_hierarchical_array(array &$array, $depth = 0, $name = null, $toDepth = 0)
{
if ($depth == 0) {
$temp = $array;
$array = array_values($array);
}
if (($name !== null) && ($depth == $toDepth)) {
$output[] = $name;
} else if ($depth < $toDepth) {
$output[] = flat_array_to_hierarchical_array(&$array, $depth + 1, $name, $toDepth);
}
while ($item = array_shift($array)) {
$newDepth = $item['depth'];
$name = $item['name'];
if ($depth == $newDepth) {
$output[] = $name;
} else if ($depth < $newDepth) {
$output[] = flat_array_to_hierarchical_array(&$array, $depth + 1, $name, $newDepth);
} else {
array_unshift($array, $item);
return $output;
}
}
$array = $temp;
return $output;
}
$arr = flat_array_to_hierarchical_array($nested_array);
echo array_to_list($arr);