为什么我的递归循环会创建太多孩子?

时间:2010-12-11 19:42:42

标签: php xml parsing recursion xml-parsing

我正在使用PHP递归循环来解析XML文档以创建嵌套列表,但是由于某种原因,循环被破坏并在列表中创建元素的副本以及空白元素。

XML(家谱树数据列表)的结构如下:

        <?xml version="1.0" encoding="UTF-8"?>
<family>
<indi>
    <id>id1</id>
    <fn>Thomas</fn>
    <bday></bday>
    <dday></dday>
    <spouse></spouse>
    <family>
            <indi>
                   <id>id1</id>
                   <fn>Alexander</fn>
                   <bday></bday>
                   <dday></dday>
                   <spouse></spouse>
                  <family>
                  </family>
           </indi>
           <indi>
                   <id>id1</id>
                   <fn>John</fn>
                   <bday></bday>
                   <dday></dday>
                   <spouse></spouse>
                   <family>
                            <indi>
                                 <id>id1</id>
                                 <fn>George</fn>
                                 <bday></bday>
                                 <dday></dday>
                                 <spouse></spouse>
                                 <family>
                                 </family>
            </indi>
                   </family>
            </indi>
    </family>
</indi>
</family>

这是我的PHP循环,它加载XML文件然后遍历它以创建嵌套的ul:

<?php 
    function outputIndi($indi) {
        echo '<li>';
        $id = $indi->getElementsByTagName('id')->item(0)->nodeValue;
        echo '<span class="vcard person" id="' . $id . '">';

        $fn = $indi->getElementsByTagName('fn')->item(0)->nodeValue;
        $bday = $indi->getElementsByTagName('bday')->item(0)->nodeValue;

        echo '<span class="edit fn">' . $fn . '</span>';
        echo '<span class="edit bday">' . $bday . '</span>';
        // ...
        echo '</span>';
        echo '<ul>';
        $family = $indi->getElementsByTagName('family');
        foreach ($family as $subIndi) {
                outputIndi($subIndi);
            }
        echo '</ul></li>';
    }

    $doc = new DOMDocument();
    $doc->load('armstrong.xml');

    outputIndi($doc);

    ?>

编辑这里是理想的结果(嵌套列表,其中ul代表家庭,li代表个人)

<ul>
  <li>
    <span class="vcard">
      <span class="fn">Thomas</span>
      <span class="bday"></span>
      <span class="dday"></span>
      <ul>
             ... repeat for all ancestors ...
      </ul>
   <li>
<ul>

您可以在http://chris-armstrong.com/gortin看到输出。我出错的任何想法?我认为这与$ subIndi值有关,但是无论何时我尝试更改它都会出错。非常感谢任何帮助!

3 个答案:

答案 0 :(得分:3)

  

听起来很完美!你能给我一个吗?   例?这是否意味着我可以保存   数据为XML,然后以嵌套方式加载   UL的?

是的,你可以做到这一点。这是一个呈现嵌套UL的XSL:

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="/">
      <html>
      <body>
        <h2>Family tree</h2>
        <ul>
            <li><xsl:value-of select="indi/fn" /></li>

            <!-- apply-templates will select all the indi/family nodes -->
            <xsl:apply-templates select="indi/family" />
        </ul>
      </body>
      </html>
    </xsl:template>

    <xsl:template match="family">       
        <ul>
            <li>
                <div>
                    <xsl:value-of select="id" />: <xsl:value-of select="fn" />
                    (<xsl:variable name="bday" select="bday" />
                    to
                    <xsl:variable name="dday" select="dday" />)
                </div>
            </li>
            <!-- This node matches the 'family' nodes, and we're going to apply-templates on the inner 'family' node,
            so this is the same thing as recursion. -->
            <xsl:apply-templates select="family" />
        </ul>
    </xsl:template>
</xsl:stylesheet>

我不知道php,但this article将向您展示如何使用上面的样式表转换XML。

您还可以通过在XML文件顶部添加样式表指令来链接样式表(请参阅for an example)。

答案 1 :(得分:0)

getElementsByTagName将为您提供所有节点,而不仅仅是直接的孩子:

$family = $indi->getElementsByTagName('family');
foreach ($family as $subIndi) {
    outputIndi($subIndi);
}

您将重复为大孩子等调用outputIndi()。

以下是一个示例(来自另一个stackoverflow question):

for ($n = $indi->firstChild; $n !== null; $n = $n->nextSibling) {
    if ($n instanceof DOMElement && $n->tagName == "family") {
        outputIndi($n);
    }
}

答案 2 :(得分:0)

替换此

$family = $indi->getElementsByTagName('family');
foreach ($family as $subIndi) {
        outputIndi($subIndi);
    }

由此

if(!empty($indi))
foreach($indi as $subIndi){  
     outputIndi($subIndi);
} 

我意识到了 如果(因迪$&GT; hasChildNodes()) 比...更好 if(!empty($ indi))