Bu cevap biraz geç muhtemelen, ama ben sorunuzu sevdim!
PHP doğrudan sorunu çözmek için yap-hiçbir ilgisi yoktur, bu yüzden XML dökümü falan yoktur.
Ancak, PHP sizin çıkış için RecursiveTreeIterator
Docs O geldiğinde oldukça yakın bulunmaktadır:
\-<html>
\-<body>
\-<p>
\-Hello World
(Kendi X (HT) ML yapısı daha karmaşık görünüyor eğer daha iyi bakacağız.)
: Bir foreach
(çoğu Yineleyicilerin gibi) oldukça basit kullanılan
$tree = new RecursiveTreeIterator($iterator);
foreach($tree as $key => $value)
{
echo $value . "\n";
}
(Bir işlev içinde bu şal, böylece yalnızca işlevini çağırmak gerekir)
Hatta bu bir ihtar var, basit görünüyor: bir RecursiveIterator
DOMDocument
ağacın üzerinde gerekiyor. PHP ne gerek tahmin edemez gibi, bu kod içine sarılmış gerekiyor. Yazılı olarak, ben soru ilginç (ve tabii ki XML çıkış için istediler değil) bulundu, bu yüzden gerekli özyinelemeli yineleyici sunduğu bazı küçük kod yazdı. Yani burada biz gitmek.
İlk olarak PHP iteratörler aşina olmayabilir. Ben kendi üzerinde bazı kod çalıştırmak için düşünün her backwards, ancak, yararlanabilirler olup olmadığını dikkate yapacağım ben göstereceğim kod yararlanmak için hiçbir anlaşma yineleyici yetenekleri PHP sunmak zorundadır. Ortak sorunları çözmek için ve gerçekten birbirleri ile çalışmak için birbirleri ile ilişkili olmayan bileşenler yapmak için yardımcı olur, çünkü bunu yazmak. Örneğin, RecursiveTreeIterator
Docs -inşa edilmiştir, ve bu (ve hatta bunu yapılandırabilirsiniz) ile beslemek şey ile çalışacaktır. Ancak a-RecursiveIterator
üzerine gereksinim duyar.
Yani bunu verelim, bir RecursiveIterator
bu teklifi <tag>
DOMNodes
içindir etiketleri (elemanlar) ve sadece text
onlar textnodes ise:
class DOMRecursiveDecoratorStringAsCurrent extends RecursiveIteratorDecoratorStub
{
public function current()
{
$node = parent::current();
$nodeType = $node->nodeType;
switch($nodeType)
{
case XML_ELEMENT_NODE:
return "<$node->tagName>";
case XML_TEXT_NODE:
return $node->nodeValue;
default:
return sprintf('(%d) %s', $nodeType, $node->nodeValue);
}
}
}
Bu DOMRecursiveDecoratorStringAsCurrent
class (adı yalnızca bir örnektir) RecursiveIteratorDecoratorStub
bazı soyut kodun kullanımı yapar. Önemli bir parçası, ancak sadece tagName
a DOMNode
in bracketsWikipedia (arasında döner ::current
fonksiyonudur <>
) ve textnodes metin olduğu gibi. Bu ne çıktı ihtiyaçları var, yani bu kod için gereken her şey.
Aslında bu sizin de soyut kodu kadar çalışmaz, ama nasıl kullanıldığını kodunu (en ilginç bölümü) görselleştirmek için, en görüntülemek edelim:
$iterator = new DOMRecursiveDecoratorStringAsCurrent($iterator);
$tree = new RecursiveTreeIterator($iterator);
foreach($tree as $key => $value)
{
echo $value . "\n";
}
Geriye doğru bitti gibi, şu an için biz hangi dayalı belirtilen çıkış DOMNode
RecursiveTreeIterator
tarafından görüntülenecek var. Şimdiye kadar, almak kolay para cezası. Ama eksik et o soyut kodu ve nasıl bir DOMElement
içindeki tüm düğümler üzerinde bir RecursiveIterator
oluşturmak için içeride. Sadece nasıl çağrılır tüm kodu önizleme (daha önce yazılı olarak, hata ayıklama amacıyla kodunuz içinde kolayca erişilebilir hale getirmek için bir fonksiyon içine koyabilirsiniz Muhtemelen adında bir fonksiyon xmltree_dump
.):
$dom = new DOMDocument();
$dom->loadHTML("<html><body><p>Hello World</p></body></html>");
$iterator = new DOMRecursiveIterator($dom->documentElement);
$iterator = new DOMRecursiveDecoratorStringAsCurrent($iterator);
$tree = new RecursiveTreeIterator($iterator);
foreach($tree as $key => $value)
{
echo $value . "\n";
}
Bu yüzden koduna ek olarak burada ne var zaten kapalı? Ilk kez orada bir DOMRecursiveIterator
- ve bu kadar. Kodun geri kalanı standart DOMDocument
kodudur.
Yani DOMRecursiveIterator
hakkında yazalım. It RecursiveIterator
nihayet RecursiveTreeIterator
içinde ihtiyaç duyulan ihtiyaç. Ağacın dökümü aslında parantez ve olduğu gibi-metinde tagnames yazdırır böylece decorated bulunuyor olsun.
Muhtemelen şimdi o kodu paylaşmak için değer:
class DOMRecursiveIterator extends DOMIterator implements RecursiveIterator
{
public function hasChildren()
{
return $this->current()->hasChildNodes();
}
public function getChildren()
{
$children = $this->current()->childNodes;
return new self($children);
}
}
Sadece iki fonksiyonları ile oldukça kısa bir sınıf bulunuyor. Bu sınıf başka sınıf uzanır gibi burada hile ediyorum. Ama yazıldığı gibi, bu geriye, yani bu sınıf aslında özyineleme ilgilenir: hasChildren
ve getChildren
. Açıkçası bile bu iki fonksiyon sadece bir standart üzerine "soru" (hasChildren
? getChildren
?) Haritalama DOMNode
edilir, fazla kod yok. Bir düğüm çocuklar varsa, iyi, evet demek ya da sadece onları geri (ve bu Yineleyicinin, bir yineleyici biçimde dönmelerini, dolayısıyla new self()
).
Bu oldukça kısa böylece, o boğulma sonra, sadece üst sınıf DOMIterator
(implements RecursiveIterator
Docs sadece etmektir devam ) çalışma yapmak:
class DOMIterator extends IteratorDecoratorStub
{
public function __construct($nodeOrNodes)
{
if ($nodeOrNodes instanceof DOMNode)
{
$nodeOrNodes = array($nodeOrNodes);
}
elseif ($nodeOrNodes instanceof DOMNodeList)
{
$nodeOrNodes = new IteratorIterator($nodeOrNodes);
}
if (is_array($nodeOrNodes))
{
$nodeOrNodes = new ArrayIterator($nodeOrNodes);
}
if (! $nodeOrNodes instanceof Iterator)
{
throw new InvalidArgumentException('Not an array, DOMNode or DOMNodeList given.');
}
parent::__construct($nodeOrNodes);
}
}
Bu DOMPHP
, it just takes a DOMNode
or a DOMNodeList
to iterate over. This sounds a bit superfluous maybe, as DOM supports this sort-of with DOMNodeList
önceden için temel yineleyici, ancak a RecursiveIterator
desteklemek ve etmez biz zaten çıkışı için RecursiveTreeIterator
için bir ihtiyaç olduğunu biliyoruz. Yani işin içinde constructor bir Iterator
oluşturuldu ve yine soyut kodu üst sınıf, üzerine geçirilir. Tabii ben sadece bir dakika içinde bu kodu ortaya edeceğiz. Bu geriye olduğu gibi, en bugüne kadar yapılmış ne gözden geçirelim:
RecursiveTreeIterator
ağaç gibi çıkış için.
DOMRecursiveDecoratorStringAsCurrent
ağacında bir DOMNode
görselleştirme
DOMRecursiveIterator
ve DOMIterator
bir DOMDocument
tüm düğümler üzerinde ardışık yineleme.
Ihtiyaç duyulan her şey gibi, bu tanım açısından, ancak ben özet olarak adlandırılan kod hala kayıp. Bu başka bir nesneye bu delegeler aynı yöntemi aşağı, sadece basit bir proxy kod çeşit bulunuyor. Bununla ilgili bir desen denir Decorator. Ancak, bu sadece kodu, ilk Iterator
ve sonra RecursiveIterator
arkadaşım:
abstract class IteratorDecoratorStub implements OuterIterator
{
private $iterator;
public function __construct(Iterator $iterator)
{
$this->iterator = $iterator;
}
public function getInnerIterator()
{
return $this->iterator;
}
public function rewind()
{
$this->iterator->rewind();
}
public function valid()
{
return $this->iterator->valid();
}
public function current()
{
return $this->iterator->current();
}
public function key()
{
return $this->iterator->key();
}
public function next()
{
$this->iterator->next();
}
}
abstract class RecursiveIteratorDecoratorStub extends IteratorDecoratorStub implements RecursiveIterator
{
public function __construct(RecursiveIterator $iterator)
{
parent::__construct($iterator);
}
public function hasChildren()
{
return $this->getInnerIterator()->hasChildren();
}
public function getChildren()
{
return new static($this->getInnerIterator()->getChildren());
}
}
Bu çok sihirli bir şey yok, sadece iyi yöntemi delege oluyor ona çağıran nesne kalıtımsal $iterator
. Bu yinelenen ve iyi Yineleyicilerde tekrarı üzeresiniz gibi görünüyor. Ben sadece bir kez bu çok basit bir kod yazmak gerekir bu yüzden soyut sınıflar bu koymak. Yani en azından ben kendimi kendimi tekrarlamak gerekmez.
Bu iki soyut sınıflar zaten daha önce tartışılan diğer sınıfları tarafından kullanılmaktadır. Bu kadar basit, çünkü, ben buraya kadar bıraktı.
Eh, çok burada dek okumak ama iyi parçası için, o kadar.
Kısacası: PHP bu inşa zorunda değildir, ancak oldukça basit kendi başınıza bu yazmak ve yeniden kullanılabilir olabilir. Daha önce yazılı olarak, xmltree_dump
adlı bir fonksiyon içine sarmak için iyi bir fikirdir böylece kolayca hata ayıklama amacıyla çağrılabilir:
function xmltree_dump(DOMNode $node)
{
$iterator = new DOMRecursiveIterator($node);
$decorated = new DOMRecursiveDecoratorStringAsCurrent($iterator);
$tree = new RecursiveTreeIterator($decorated);
foreach($tree as $key => $value)
{
echo $value . "\n";
}
}
Kullanımı:
$dom = new DOMDocument();
$dom->loadHTML("<html><body><p>Hello World</p></body></html>");
xmltree_dump($dom->documentElement);
ihtiyaç duyulan tek şey, kullanılan tüm sınıf tanımları gerekli / dahil olmasıdır. Siz bir dosyaya yerleştirin ve require_once
kullanmak ya da muhtemelen kullandığınız bir otomatik yükleyici ile entegre edebilirsiniz. Full code at once.
Eğer çıkış yolu düzenlemek gerekiyorsa, DOMRecursiveDecoratorStringAsCurrent
düzenlemek veya RecursiveTreeIterator
xmltree_dump
içindeki yapılandırmasını değiştirebilirsiniz. Bu (backwards in-direkt oldukça hatta oldukça uzun olduğunu) yararlı olduğunu umuyoruz.