PHP XML到动态表 [英] PHP XML to dynamic table

查看:96
本文介绍了PHP XML到动态表的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

 < ticket 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>
< / ticket>

每个票是一个新表,每个行是一行,行是一列(除了0,这将是一个空单元格)。



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



我该怎么做?

解决方案

我在问题 PHP simplexml xpath搜索包含制表符分隔文本的ELEMENT中的值? ,显示如何操作包含编码数据的SimpleXMLElement,使其变为更多可访问的数据。



可以在您的情况下完成相似的操作,但这次我想显示如何使用自定义迭代器完成此操作。

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



同时你的问题还有另外一个迭代器。所以在伪代码中可以看起来像:

  foreach($ tables as $ table)
{
foreach($ table as $ rows){
foreach($ rows as $ column){
}
}
}
/ pre>

在这个地方执行输出。所以例如,如果我们有一个迭代器能够迭代行和列,以便转换成一个表(例如,到目前为止演示的纯文本),伪代码可以减少到:

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

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



为此,我向您介绍一个名为 DecoratingIterator 。它允许在迭代中装饰每个当前元素。这是非常灵活的,因为我们可以使用它以一个非常灵活的方式在小步骤中组成最终的table-iterator。



让我们解决你面临的所有问题,步。首先需要一个函数来将数字0变成一个空字符串。让我们为此创建一个函数(如果需要,我还需要添加一些更多的格式,如果需要,可以加上空格):

  $ 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){
返回新的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 iterator可以用来显示表。所以为了使这更容易使用,我们把它包装成一个它自己的类型,这个类可以聚合一个迭代器,它通过 IteratorAggregate interface:

  class TableAggregator实现IteratorAggregate 
{
private $ xml;

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

public function getIterator()
{
#...代码创建表iterator

return $ tables;
}
}

好的,这可能是迄今为止。更好地显示使用情况,现在可以使可见为什么聚合在这里有意义:

  $ xml =使用simplexml_load_file( '的example.xml'); 

$ tables = new TableAggregator($ xml);

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

正如这个例子所示,它的原因很简单。另外,如果我们有不同的格式需求,我们可以创建一个不同的聚合器 - 简单的是。让我们看看示例性的输出:

  +  -  +  -  +  -  +  -  +  -  +  -  +  -  -  +  -  +  -  + 
| | 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


I'm trying to create a dynamic table based on an XML. The outputted XML is the following:

<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>

Each "ticket" is a new table, each "row" is a row and each number in the row is a column (except for the 0, that will be an empty cell).

I know I should be using PHP's SimpleXML, but I have no idea how.

How do I go about doing this?

解决方案

I've given an extensive example in the question PHP simplexml xpath search for value in an ELEMENT containing tab delimited text? that shows how you can manipulate a SimpleXMLElement on-the-fly containing encoded data turning it into more accessible data.

This could be done similarly in your case, however this time I'd like to to show how this can be done with custom iterators.

But first let's consider how a table could be represented: A table consists of rows and columns. So we could iterate over rows and each row could be an iterator of columns.

And with your question, there is also another iterator over the tables. So in pseudo-code this can look like:

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

Doing the output somewhere around that. So for example, if we have got an Iterator that is able to iterate over rows and columns that way to convert is into a table (for example as plain text for demonstration purposes so far), the pseudo-code can be reduced to this:

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

As this example shows, the problem has been already reduced to display a single table - because all tables follow the same structure. I do not show TextTable works right now, it's not of further interest. If you are looking for an iterator that outputs a HTML table following the same iteration, see the linked question above, it has got a HtmlTableIterator which does most of the work. But right now, let's look how to create the iterator over rows and columns.

For that I introduce you to an existing iterator class named DecoratingIterator. It allows to decorate each current element in an iteration. This is pretty flexible because we can use it to compose the final table-iterator in a pretty flexible way in small steps.

Let's solve all the problems you face, step by step. First of all a function is needed to turn the number 0 into an empty string. Let's create a function for that (and I also add some more formatting by prefixing with spaces if necessary to get a length of two):

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

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

The next problem to solve is to turn the SimpleXMLElement of numbers into something foreach-able that are those formatted numbers. Let's just write it as well and use the previous function to help get it done:

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

Wow, that was short. The next problem to solve is to turn all rows of a single table into these array of numbers. Well, again, we do it with the help of the last function:

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

And finally one problem is left: The whole XML needs to be turned into an iterator of all the tables. Again with the previous function this is more easy again:

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

Wow. Probably a bit long, let's review:

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

All these lines of code do is to provide the $tables iterator we can use to display the tables. So to make this more easy to use, we wrap this into a class of it's own and signal PHP that this class can aggregate an iterator which works via the IteratorAggregate interface:

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

Okay, that probably was a lot so far. Better show the usage-example now to make visible why aggregation makes sense here:

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

$tables = new TableAggregator($xml);

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

As this example shows, its because this is easy to use. Also if we have a different formatting needs, we could create a different aggregator - that simple it is. Let's see the exemplary output:

+--+--+--+--+--+--+--+--+--+
|  |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|
+--+--+--+--+--+--+--+--+--+

The whole example at a glance: https://gist.github.com/hakre/5734770

这篇关于PHP XML到动态表的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆