【问题标题】:Output from sorted array with SimpleXML, xsort and xpath in PHPPHP 中使用 SimpleXML、xsort 和 xpath 的排序数组的输出
【发布时间】:2015-11-09 20:15:01
【问题描述】:

解决了这个 XML 解析项目的一系列其他问题(感谢一位可爱的 SO 用户),我现在陷入了下一个障碍。我正在将 SimpleXML 加载到一个数组中,对其进行排序,然后将其回显到页面中,并对数据进行分组。

我可以显示我的组标题并正确排序,但是当我尝试添加子组数据(这需要 xpath 将属性与父组匹配)时,我的输出只是第一个组标题。不确定这是否是我将数组结果与 xpath 混合的方式,但希望这里有人可以立即发现问题。

这是我的 XML:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE besteplist SYSTEM "example.dtd">
<besteplist>
    <yearlist>
        <year yid="y1">
            <yearname>1995, Season 3</yearname>
        </year>
        <year yid="y2">
            <yearname>1996, Season 4</yearname>
        </year>
        <year yid="y3">
            <yearname>1997, Season 5</yearname>
        </year>
        <year yid="y4">
            <yearname>1994, Season 2</yearname>
        </year>
        <year yid="y5">
            <yearname>1993, Season 1</yearname>
        </year>
    </yearlist>
    <eplist>
        <ep yearid="y1" eid="e1">
            <eptitle>The Third Episode</eptitle>
            <eptnumber>3</eptnumber>
        </ep>
        <ep yearid="y2" eid="e2">
            <eptitle>Bla bla bla</eptitle>
            <eptnumber>21</eptnumber>
        </ep>
        <ep yearid="y2" eid="e3">
            <eptitle>Rar rar rar</eptitle>
            <eptnumber>39</eptnumber>
        </ep>
        <ep yearid="y2" eid="e4">
            <eptitle>Tra la la</eptitle>
            <eptnumber>45</eptnumber>
        </ep>
        <ep yearid="y3" eid="e5">
            <eptitle>Donkey</eptitle>
            <eptnumber>126</eptnumber>
        </ep>
        <ep yearid="y1" eid="e6">
            <eptitle>SHOULD APPPEAR AS FIRST ONCE SORTED</eptitle>
            <eptnumber>1</eptnumber>
        </ep>
    </eplist>
</besteplist>

我希望按 yearname 升序对组标题进行排序,并按 eptnumber 升序对子组结果进行排序。

到目前为止,这是我的 PHP 代码:

<?php
$xml=simplexml_load_file("example.xml") or die("Error: Cannot create object");

function xsort(&$sorted_year, $child_name, $order=SORT_ASC)
{
    $sort_proxy = array();

    foreach ($sorted_year as $k => $node) {
        $sort_proxy[$k] = (string) $node->$child_name;
    }

    array_multisort($sort_proxy, $order, $sorted_year);
}

$sorted_year = $xml->xpath('/besteplist/yearlist/year');
xsort($sorted_year, 'yearname', SORT_ASC);

$sorted_ep = $xml->xpath('/besteplist/eplist/ep');
xsort($sorted_ep, 'eptnumber', SORT_ASC);

foreach ($sorted_year as $season) {
    echo "SEASON: " . $season->yearname . "<br>";
    foreach ($sorted_ep->xpath("//ep[@yearid='$season[yid]']") as $episode) { 
        echo "EPISODE TITLE: " . $episode->eptitle . PHP_EOL . "<br>";
        echo "EPISODE NUMBER: " . $episode->eptnumber . PHP_EOL . "<br>"; 
        echo PHP_EOL . "<br>";
    }
}


?>

这是我在任何排序之前的输出:

SEASON: 1995, Season 3
EPISODE TITLE: The Third Episode 
EPISODE NUMBER: 3 

EPISODE TITLE: SHOULD APPPEAR AS FIRST ONCE SORTED 
EPISODE NUMBER: 1 

SEASON: 1996, Season 4
EPISODE TITLE: Bla bla bla 
EPISODE NUMBER: 21 

EPISODE TITLE: Rar rar rar 
EPISODE NUMBER: 39 

EPISODE TITLE: Tra la la 
EPISODE NUMBER: 45 

SEASON: 1997, Season 5
EPISODE TITLE: Donkey 
EPISODE NUMBER: 126 

SEASON: 1994, Season 2
SEASON: 1993, Season 1

它应该是这样的:

SEASON: 1993, Season 1

SEASON: 1994, Season 2

SEASON: 1995, Season 3
EPISODE TITLE: SHOULD APPPEAR AS FIRST ONCE SORTED 
EPISODE NUMBER: 1 

EPISODE TITLE: The Third Episode 
EPISODE NUMBER: 3 

SEASON: 1996, Season 4
EPISODE TITLE: Bla bla bla 
EPISODE NUMBER: 21 

EPISODE TITLE: Rar rar rar 
EPISODE NUMBER: 39 

EPISODE TITLE: Tra la la 
EPISODE NUMBER: 45 

SEASON: 1997, Season 5
EPISODE TITLE: Donkey 
EPISODE NUMBER: 126 

非常感谢您能发现问题或提出改进建议。显然这是基于相同结构的示例/示例数据。

山姆

更新

仍然没有设法做到这一点,并且无法发现我在哪一点上出错了。最好的猜测是 foreach 语句中的 xpath,但我对这种类型的代码还不够熟悉,无法发现它。

我已经为 sort_obj_arr 切换了 xsort,因为我认为它是一个更好的函数。不幸的是,我得到的结果与以前完全相同。这是我更新的代码:

<?php
$xml=simplexml_load_file("example.xml") or die("Error: Cannot create object");

function sort_obj_arr(& $arr, $sort_field, $sort_direction) {
    $sort_func = function($obj_1, $obj_2) use ($sort_field, $sort_direction) {
        if ($sort_direction == SORT_ASC) {
            return strnatcasecmp($obj_1->$sort_field, $obj_2->$sort_field);
        } else {
            return strnatcasecmp($obj_2->$sort_field, $obj_1->$sort_field);
        }
    };
    usort($arr, $sort_func);
}

$sorted_year = $xml->xpath('/besteplist/yearlist/year');
$field1 = 'yearname';
$direction1 = SORT_ASC;
sort_obj_arr($sorted_year, $field1, $direction1);

$sorted_ep = $xml->xpath('/besteplist/eplist/ep');
$field2 = 'eptnumber';
$direction2 = SORT_ASC;
sort_obj_arr($sorted_ep, $field2, $direction2);

foreach ($sorted_year as $season) {
    echo "SEASON: " . $season->yearname . "<br>";
    foreach ($sorted_ep->xpath("//ep[@yearid='$season[yid]']") as $episode) { 
        echo "EPISODE TITLE: " . $episode->eptitle . PHP_EOL . "<br>";
        echo "EPISODE NUMBER: " . $episode->eptnumber . PHP_EOL . "<br>"; 
        echo PHP_EOL . "<br>";
    }
}

?>

【问题讨论】:

  • 我猜我的 xpath 引用数组是不正确的,但我对代码还不够熟悉,无法发现错误,因为我有点想这么做。已更新我的问题。
  • 是时候学习调试代码了。您的猜测非常正确,您是否收到错误消息?见eval.in/468492。您对 ep 排序太早,您需要在选择相关的后对其进行排序。
  • 不幸的是,我的 PHP 设置没有给我错误代码 - 我将不得不开始使用 eval.in 进行测试。我试过重新排列,但现在得到eval.in/468509
  • 在 PHP 中获取有用的错误消息:stackoverflow.com/questions/845021/…

标签: php arrays xml sorting xpath


【解决方案1】:

你的代码

foreach ($sorted_ep->xpath("//ep[@yearid='$season[yid]']") as $episode)

抛出错误

Fatal error: Call to a member function xpath() on a non-object (...)

因为$sorted_ep 是一个数组,而不是SimpleXml 对象。

在您的 XML 中获取 all &lt;ep&gt; 的排序列表是没有意义的。您需要选择某一年的剧集,然后对它们进行排序:

foreach ($sorted_year as $season) {
    echo "SEASON: " . $season->yearname . "<br><br>";

    // first select episodes from a certain year 
    $episodes = $xml->xpath("//ep[@yearid='$season[yid]']");

    // then sort those
    sort_obj_arr($episodes, "eptnumber", SORT_ASC);

    // now iterate and echo
    foreach ($episodes as $episode) { 
        echo "  EPISODE TITLE: " . $episode->eptitle . "<br>";
        echo "  EPISODE NUMBER: " . $episode->eptnumber . "<br><br>"; 
    }
}

查看实际操作:https://eval.in/468571

【讨论】:

  • 我知道我们不应该感谢这些 cmets 的人,但我觉得不表达我的感激之情很粗鲁。只想说谢谢你所有的帮助! :)
  • 谢谢,很高兴能分享。
猜你喜欢
  • 1970-01-01
  • 2012-01-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多