【问题标题】:PHP XML to dynamic tablePHP XML 到动态表
【发布时间】:2013-06-08 09:02:25
【问题描述】:

我正在尝试创建一个基于 XML 的动态表。输出的 XML 如下:

<tickets xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <status>1</status>
    <message>
        <ticketpage>
            <ticket>
                <row1>0-10-27-30-45-0-0-0-80</row1>
                <row2>0-15-0-38-0-51-62-0-85</row2>
                <row3>5-0-0-37-0-57-60-77-0</row3>
            </ticket>
            <ticket>
                <row1>0-0-20-33-0-56-68-0-90</row1>
                <row2>8-0-0-0-49-0-64-71-84</row2>
                <row3>1-18-22-32-0-59-0-0-0</row3>
            </ticket>
            <ticket>
                <row1>0-0-23-0-47-58-67-0-86</row1>
                <row2>4-16-0-0-43-53-0-0-88</row2>
                <row3>3-0-28-35-0-0-65-72-0</row3>
            </ticket>
            <ticket>
                <row1>0-19-26-0-48-52-0-74-0</row1>
                <row2>0-0-21-0-40-0-63-75-82</row2>
                <row3>9-11-0-34-41-0-0-76-0</row3>
            </ticket>
            <ticket>
                <row1>0-12-29-36-44-0-0-78-0</row1>
                <row2>6-14-0-39-0-0-69-0-89</row2>
                <row3>2-0-0-0-0-54-66-70-81</row3>
            </ticket>
            <ticket>
                <row1>0-17-25-0-46-0-0-73-87</row1>
                <row2>0-0-24-0-42-50-61-79-0</row2>
                <row3>7-13-0-31-0-55-0-0-83</row3>
            </ticket>
        </ticketpage>
    </message>
</tickets>

每个“票”是一个新表,每个“行”是一行,行中的每个数字是一列(0 除外,这将是一个空单元格)。

我知道我应该使用 PHP 的 SimpleXML,但我不知道如何。

我该怎么做呢?

【问题讨论】:

  • 关于 SimpleXMLElement 的一般教程可以在这里找到:php.net/simplexml.examples-basic - 您可以从编写一些加载 XML 文档的代码开始。然后你解析它,通常通过迭代它。

标签: php xml dynamic xmltable


【解决方案1】:

我在问题 PHP simplexml xpath search for value in an ELEMENT containing tab delimited text? 中给出了一个广泛的示例,它展示了如何即时操作包含编码数据的 SimpleXMLElement,将其转换为更易于访问的数据。

在您的情况下,这可以类似地完成,但是这次我想展示如何使用自定义迭代器来完成。

但首先让我们考虑如何表示一个表:一个表由行和列组成。所以我们可以迭代行,每一行都可以是列的迭代器。

关于您的问题,表上还有另一个迭代器。所以在伪代码中,这可能看起来像:

foreach($tables as $table)
{
    foreach ($table as $rows) {
        foreach ($rows as $column) {
        }
    }
}

在这附近的某个地方进行输出。因此,例如,如果我们有一个迭代器,它能够迭代行和列以将其转换为表(例如到目前为止用于演示目的的纯文本),伪代码可以简化为:

foreach($tables as $table)
{
    echo new TextTable($table);
}

正如本例所示,问题已经简化为显示单个表格 - 因为所有表格都遵循相同的结构。我现在不显示TextTable 的作品,它没有进一步的兴趣。如果您正在寻找在同一迭代之后输出 HTML 表的迭代器,请参阅上面的链接问题,它有一个 HtmlTableIterator 可以完成大部分工作。但是现在,让我们看看如何在行和列上创建迭代器。

为此,我向您介绍一个名为DecoratingIterator 的现有迭代器类。它允许在迭代中装饰每个 current 元素。这非常灵活,因为我们可以使用它以非常灵活的方式分小步组合最终的表迭代器。

让我们一步一步解决您面临的所有问题。首先需要一个函数将数字 0 转换为空字符串。让我们为此创建一个函数(如果需要,我还添加了更多格式,通过在前面加上空格来获得长度为 2):

$formatNumber = function($number)
{
    if ($number === '0') {
        $number = '';
    }

    return sprintf("%' 2s", $number);
};

下一个要解决的问题是将SimpleXMLElement 的数字转换为可用于格式化的数字。让我们也编写它并使用之前的函数来帮助完成它:

$numbersToArray = function($stringNumbers) use ($formatNumber) {
    return array_map($formatNumber, explode('-', $stringNumbers));
};

哇,太短了。下一个要解决的问题是将单个表的所有行转换为这些数字数组。好吧,再一次,我们在最后一个函数的帮助下做到了:

$tableToRows = function(SimpleXMLElement $table) use ($numbersToArray) {
    return new DecoratingIterator($table->children(), $numbersToArray);
};

最后还有一个问题:需要将整个 XML 转换为所有表的迭代器。再次使用之前的函数,这再次变得更加简单:

$tables = new DecoratingIterator(
    $xml->message->ticketpage->ticket,
    $tableToRows
);

哇。可能有点长,我们回顾一下:

$formatNumber = function($number)
{
    if ($number === '0') {
        $number = '';
    }

    return sprintf("%' 2s", $number);
};

$numbersToArray = function(SimpleXMLElement $stringNumbers) use ($formatNumber) {
    return array_map($formatNumber, explode('-', $stringNumbers));
};

$tableToRows = function(SimpleXMLElement $table) use ($numbersToArray) {
    return new DecoratingIterator($table->children(), $numbersToArray);
};

$tables = new DecoratingIterator(
    $xml->message->ticketpage->ticket,
    $tableToRows
);

所有这些代码行的作用是提供$tables 迭代器,我们可以使用它来显示表格。所以为了让它更易于使用,我们将它包装到它自己的一个类中并且告诉 PHP 这个类可以聚合一个通过IteratorAggregate 接口工作的迭代器:

class TableAggregator implements IteratorAggregate
{
    private $xml;

    public function __construct(SimpleXMLElement $xml)
    {
        $this->xml = $xml;
    }

    public function getIterator() 
    {
        # ... code to create the tables iterator

        return $tables;
    }
}

好的,到目前为止可能已经很多了。现在更好地展示用法示例,以使 why 聚合在这里有意义:

$xml = simplexml_load_file('example.xml');

$tables = new TableAggregator($xml);

foreach ($tables as $table) {
    echo new TextTable($table), "\n";
}

正如本例所示,这是因为它易于使用。此外,如果我们有不同的格式化需求,我们可以创建一个不同的aggregator - 就是这么简单。让我们看看示例输出:

+--+--+--+--+--+--+--+--+--+
|  |10|27|30|45|  |  |  |80|
+--+--+--+--+--+--+--+--+--+
|  |15|  |38|  |51|62|  |85|
+--+--+--+--+--+--+--+--+--+
| 5|  |  |37|  |57|60|77|  |
+--+--+--+--+--+--+--+--+--+

+--+--+--+--+--+--+--+--+--+
|  |  |20|33|  |56|68|  |90|
+--+--+--+--+--+--+--+--+--+
| 8|  |  |  |49|  |64|71|84|
+--+--+--+--+--+--+--+--+--+
| 1|18|22|32|  |59|  |  |  |
+--+--+--+--+--+--+--+--+--+

+--+--+--+--+--+--+--+--+--+
|  |  |23|  |47|58|67|  |86|
+--+--+--+--+--+--+--+--+--+
| 4|16|  |  |43|53|  |  |88|
+--+--+--+--+--+--+--+--+--+
| 3|  |28|35|  |  |65|72|  |
+--+--+--+--+--+--+--+--+--+

+--+--+--+--+--+--+--+--+--+
|  |19|26|  |48|52|  |74|  |
+--+--+--+--+--+--+--+--+--+
|  |  |21|  |40|  |63|75|82|
+--+--+--+--+--+--+--+--+--+
| 9|11|  |34|41|  |  |76|  |
+--+--+--+--+--+--+--+--+--+

+--+--+--+--+--+--+--+--+--+
|  |12|29|36|44|  |  |78|  |
+--+--+--+--+--+--+--+--+--+
| 6|14|  |39|  |  |69|  |89|
+--+--+--+--+--+--+--+--+--+
| 2|  |  |  |  |54|66|70|81|
+--+--+--+--+--+--+--+--+--+

+--+--+--+--+--+--+--+--+--+
|  |17|25|  |46|  |  |73|87|
+--+--+--+--+--+--+--+--+--+
|  |  |24|  |42|50|61|79|  |
+--+--+--+--+--+--+--+--+--+
| 7|13|  |31|  |55|  |  |83|
+--+--+--+--+--+--+--+--+--+

整个例子一目了然:https://gist.github.com/hakre/5734770

【讨论】:

  • 天哪,这真的很有启发性。
  • 这很奇怪,它说它找不到 DecoratingIterator 类。不过,我已经添加了 Iterator-Garden。
  • @AlexGorcea:以iterator-garden的开发分支为例。对不起,我没有说清楚。然而,自述文件中也链接了这一类,它一开始不是我写的,而是有好几年的历史了。见:github.com/hakre/Iterator-Garden/blob/development/src/… 最初在这里:code.google.com/p/cvphplib/source/browse/trunk/cvphplib/code/…
  • 像魅力一样工作。不过,我将不得不处理格式问题,将其设为 。
  • 在我发布包含HtmlTable 类的答案几分钟后,我确实更新了要点,这可能会给你一个想法。
【解决方案2】:

你可以试试这个:

<?php
$str = '<tickets xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
            <status>1</status>
            <message>
                <ticketpage>
                    <ticket>
                        <row>0-10-27-30-45-0-0-0-80</row>
                        <row>0-15-0-38-0-51-62-0-85</row>
                        <row>5-0-0-37-0-57-60-77-0</row>
                    </ticket>
                </ticketpage>
            </message>
        </tickets>';
$dom = new SimpleXMLElement($str);
foreach ($dom->message->ticketpage->ticket as $ticket) {
    echo '<table border=1>';
    foreach($ticket->row as $row){
        $cellList = explode('-',$row);
        echo '<tr>';
        foreach ($cellList as $cell){
            echo '<td>', $cell, '</td>';
        }
        echo '</tr>';
    }
    echo '</table>';
}

【讨论】:

  • 效果很好,我什至把零变成了空格(对我来说很重要)。
  • 但是,它只输出一个票节点。
  • 因为示例数据只有一个节点
  • 移动 echo $html;到 $html .= ''; 之后
  • 太棒了,这很有帮助。
猜你喜欢
  • 1970-01-01
  • 2013-02-22
  • 1970-01-01
  • 2017-01-26
  • 1970-01-01
  • 2023-03-26
  • 1970-01-01
  • 1970-01-01
  • 2012-11-06
相关资源
最近更新 更多