我在PHP simplexml xpath search for value in an ELEMENT contains 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
. 它允许在迭代中装饰每个当前元素。这是非常灵活的,因为我们可以使用它以非常灵活的方式以小步骤组成最终的表迭代器。
让我们一步一步解决您面临的所有问题。首先需要一个函数将数字 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;
}
}
好吧,到目前为止可能已经很多了。现在更好地展示用法示例,以说明为什么聚合在这里有意义:
$xml = simplexml_load_file('example.xml');
$tables = new TableAggregator($xml);
foreach ($tables as $table) {
echo new TextTable($table), "\n";
}
如本例所示,这是因为它易于使用。此外,如果我们有不同的格式化需求,我们可以创建一个不同的聚合器——就是这么简单。让我们看看示例输出:
+--+--+--+--+--+--+--+--+--+
| |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