【问题标题】:Why is my recursive loop creating too many children?为什么我的递归循环创建了太多的孩子?
【发布时间】:2010-12-11 19:42:41
【问题描述】:

我正在使用 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 值有关,但是每当我尝试更改它时,都会出现错误。非常感谢任何帮助!

【问题讨论】:

  • 这看起来像是 xsl 的工作,您是否考虑改为 xsl 转换?
  • 不好意思说我从来没有听说过 xsl,它是什么?
  • XSL 用于将 XML 从一种格式转换为另一种格式,请参阅 w3schools.com/xsl/default.asp。在您的情况下,您可以毫不费力地获取家谱并生成 XHTML 文档。
  • 听起来很完美!你能给我举个例子吗?这是否意味着我可以将数据保存为 XML,然后将其作为嵌套的 ul 加载?
  • @Chris,要获得准确的帮助,发布您想要的输出示例会很有帮助。

标签: php xml parsing recursion xml-parsing


【解决方案1】:

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

是的,您完全可以这样做。这是一个呈现嵌套 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 感谢将其识别为 XSLT 的应用程序,并且 OP 没有考虑它。请注意,要获得 OP 似乎想要的结果,您需要将 xsl:apply-templates (两次)放入 &lt;li&gt; 元素中。 (@Chris 也是。)
  • 天哪,太美了!不过有一件事,如果我想获取 'id' 值,并使用它来创建每个 li 的 id 属性......我会怎么做? ) 似乎打破了它:/
  • @Chris Armstrong:&lt;xsl:element name="li"&gt;&lt;xsl:attribute name="id"&gt;&lt;xsl:value-of select="id" /&gt;&lt;/xsl:attribute&gt;&lt;/xsl:element&gt;。可怕的丑陋语言,amirite ;)
  • 哈哈有点意思,但它仍然比解析优雅得多! :D 非常感谢,现在只是想弄清楚如何在 php 中启用 XSLT 功能...
【解决方案2】:

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);
    }
}

【讨论】:

【解决方案3】:

替换这个

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

通过这个

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

我意识到
if($indi->hasChildNodes()) 比
if(!empty($indi))

【讨论】:

  • 谢谢,我现在已经尝试过了,但它只是给了我第一个孩子(Thomas),知道可能出了什么问题吗?
  • 谢谢,也试过 if($indi->hasChildNodes()) 但还是没有成功
猜你喜欢
  • 2017-07-19
  • 1970-01-01
  • 1970-01-01
  • 2013-10-31
  • 2019-11-12
  • 1970-01-01
  • 1970-01-01
  • 2021-05-04
  • 1970-01-01
相关资源
最近更新 更多