【问题标题】:PHP sorting issue with simpleXMLsimpleXML 的 PHP 排序问题
【发布时间】:2010-06-11 13:18:04
【问题描述】:

test.xml:

<?xml version="1.0"?>
<props>
<prop>
<state statename="Mississippi">
    <info>
        <code>a1</code>
        <location>Jackson</location>
    </info>
    <info>
        <code>d2</code>
        <location>Gulfport</location>
    </info>
    <info>
        <code>g6</code>
        <location>Hattiesburg</location>
    </info>
</state>
<state statename="Texas">
    <info>
        <code>i9</code>
        <location>Dallas</location>
    </info>
    <info>
        <code>a7</code>
        <location>Austin</location>
    </info>
</state>
<state statename="Maryland">
    <info>
        <code>s5</code>
        <location>Mount Laurel</location>
    </info>
    <info>
        <code>f0</code>
        <location>Baltimore</location>
    </info>
    <info>
        <code>h4</code>
        <location>Annapolis</location>
    </info>
</state>
</prop>
</props>

test.php

// start the sortCities
function sortCities($a, $b){
    return strcmp($a->location, $b->location);
}
// start the sortStates
function sortStates($t1, $t2) {
    return strcmp($t1['statename'], $t2['statename']);
}


$props = simplexml_load_file('test.xml');
foreach ($props->prop as $prop) {
    $sortedStates = array();
    foreach($prop->state as $states) {
        $sortedStates[] = $states;
        }
    usort($sortedStates, "sortStates"); // finish the sortStates
    /* --- */
    echo '<pre>'."\n";
    print_r($sortedStates);
    echo '</pre>'."\n"; 
    /* --- */
    foreach ($prop->children() as $stateattr) { // this doesn't do it
    //foreach($sortedStates as $hotel => @attributes){ // blargh!
        if(isset($stateattr->info)) {
            $statearr = $stateattr->attributes();
            echo '<optgroup label="'.$statearr['statename'].'">'."\n";
            $options = array();
            foreach($stateattr->info as $info) {
                $options[] = $info;                            
            }
            usort($options, "sortCities"); // finish the sortCities  
            foreach($options as $stateattr => $info){
                echo '<option value="'.$info->code.'">'.$info->location.'</option>'."\n";
            }
            echo '</optgroup>'."\n";
            } else {
                //empty nodes don't do squat
            }
    }
}  
?>

这是数组:

print_r($sortedStates);

打印出来:

Array
(
    [0] => SimpleXMLElement Object
        (
            [@attributes] => Array
                (
                    [statename] => Maryland
                )

            [info] => Array
                (
                    [0] => SimpleXMLElement Object
                        (
                            [code] => s5
                            [location] => Mount Laurel
                        )

                    [1] => SimpleXMLElement Object
                        (
                            [code] => f0
                            [location] => Baltimore
                        )

                    [2] => SimpleXMLElement Object
                        (
                            [code] => h4
                            [location] => Annapolis
                        )

                )

        )

    [1] => SimpleXMLElement Object
        (
            [@attributes] => Array
                (
                    [statename] => Mississippi
                )

            [info] => Array
                (
                    [0] => SimpleXMLElement Object
                        (
                            [code] => a1
                            [location] => Jackson
                        )

                    [1] => SimpleXMLElement Object
                        (
                            [code] => d2
                            [location] => Gulfport
                        )

                    [2] => SimpleXMLElement Object
                        (
                            [code] => g6
                            [location] => Hattiesburg
                        )

                )

        )

    [2] => SimpleXMLElement Object
        (
            [@attributes] => Array
                (
                    [statename] => Texas
                )

            [info] => Array
                (
                    [0] => SimpleXMLElement Object
                        (
                            [code] => i9
                            [location] => Dallas
                        )

                    [1] => SimpleXMLElement Object
                        (
                            [code] => a7
                            [location] => Austin
                        )

                )

        )

)

这个:

// start the sortCities
function sortCities($a, $b){
    return strcmp($a->location, $b->location);
}

加上这部分代码:

    $options = array();
    foreach($stateattr->info as $info) {
        $options[] = $info;                            
    }
    usort($options, "sortCities"); // finish the sortCities  
    foreach($options as $stateattr => $info){
        echo '<option value="'.$info->code.'">'.$info->location.'</option>'."\n";
    }

在按每个 optgroup 中的“位置”节点排序方面做得很好。

您可以看到,在数组中我可以通过属性“statename”对其进行排序。我遇到的问题是呼应并结合这两个功能,以便让它自动对州和城市进行排序,并形成所需的 optgroup。

我尝试复制城市的行并更改名称,但无济于事。

所以使用上面的 XML 结构,我试图让它看起来像:

<optgroup label="Maryland">
<option value="h4">Annapolis</option>
<option value="f0">Baltimore</option>
<option value="s5">Mount Laurel</option>
</optgroup>
<optgroup label="Mississippi">
<option value="d2">Gulfport</option>
<option value="g6">Hattiesburg</option>
<option value="a1">Jackson</option>
</optgroup>
<optgroup label="Texas">
<option value="a7">Austin</option>
<option value="i9">Dallas</option>
</optgroup>

因此,无论状态在 XML 中的排列顺序如何,也无论位置在状态内的节点中如何排列,它们总是在创建 optgroup 时按字母顺序排列。


人工制品-

最后 2 个代码块显示了按名称(位置节点)对节点进行排序的功能。


// start the sortCities
function sortCities($a, $b){
    return strcmp($a->location, $b->location);
}
// start the sortStates
function sortStates($t1, $t2) {
    return strcmp($t1['statename'], $t2['statename']);
}

第二个函数确实按数组中的属性 (statename) 排序,但是,将这两个函数组合起来,或者更确切地说将它们嵌套起来,以便按字母顺序对州和城市进行排序,这让我很难过。


@Artefacto,

感谢您的回复。它的嵌套方式似乎很有意义。问题是,我的服务器都没有运行 PHP 5.3。所以泛型函数正在抛出错误。我应该提到这一点,但没有考虑。他们正在运行 5.2。我一直在尝试恢复脚本,但遇到了一个部分。

<?php
$doc = simplexml_load_file('test.xml');
$states =  get_object_vars($doc->prop->children());
$states = $states["state"];
function sortStates($t1, $t2) { 
    return strcmp($t1['statename'], $t2['statename']); 
};
usort($states, "sortStates");

/* this is just here for testing */
echo '<pre>';
print_r($states);
echo '</pre>';
/* end testing */

/*
array_walk($states,
    function (&$state) {
        $state = get_object_vars($state);
        array_walk($state["info"],
            function (&$el) {
                $el = get_object_vars($el);
            }
        );
        usort($state["info"],
            function($a, $b) { return strcmp($a["location"], $b["location"]); }
        );
    }
);
*/
?>

以array_walk 开头的注释掉的部分。我不知道如何在下一行死掉的情况下重写“函数(&$state)”。

【问题讨论】:

  • 不要让我们阅读代码来了解您想要做什么。以尽可能简洁的方式告诉我们您想要做什么,然后向我们展示代码。然后我们可以在上下文中阅读它,这比从代码中猜测更容易。
  • “我遇到的麻烦是呼应并结合这两个功能,以便让它自动对州和城市进行排序,并形成所需的 optgroup。”我这样做了。感谢您的参与。
  • 哪两个函数? sn-ps 中没有任何功能。这些功能应该做什么?自动排序?与非自动排序相反?刻薄无助于您的事业。
  • 你应该展示一个你想要达到的目标的例子,而不是你实际得到的。

标签: php simplexml


【解决方案1】:

您想根据某个属性或元素值对SimpleXMLElements 列表进行排序。您通常通过将列表转换为数组然后在该数组上应用排序来做到这一点。

在 PHP 中对此有用的函数是 iterator_to_array。它可以将 simplexml 中如此神奇的东西变成一个更“固定”的数组。

假设您在$result-&gt;tour 中的游览元素。默认情况下,simplexml 在此处返回一个 iterator,这是您无法开箱即用的。让我们把它转换成一个数组:

$tours = iterator_to_array($result->tour, false);

现在$tours 变量是一个数组,其中包含每个&lt;tour&gt; 元素作为SimplXMLElement。您现在可以使用数组函数对该数组进行排序。那些array sorting functions are outlined in the PHP manual 和我通常建议How do I sort a multidimensional array in php 作为一个很好的起点:

$tourDates = array_map(
    function($tour) {return trim($tour->next_bookable_date); },
    $tours
);

// sort $tours array by dates, highest to lowest
$success = array_multisort($tourDates, SORT_DESC, $tours);

就是这样。整个代码一目了然:

$tours = iterator_to_array($result->tour, false);

$tourDates = array_map(
    function($tour) {return trim($tour->next_bookable_date); },
    $tours
);

// sort $tours array by dates, highest to lowest
$success = array_multisort($tourDates, SORT_DESC, $tours);

foreach ($tours as $tour) {
    ...
}

【讨论】:

    【解决方案2】:

    我的方法是将 SimpleXMLElement 对象转换为数组:

    $doc = new SimpleXMLElement($xml);
    $states =  get_object_vars($doc->prop->children());
    $states = $states["state"];
    usort($states, function($t1, $t2) { return strcmp($t1['statename'], $t2['statename']); });
    array_walk($states,
        function (&$state) {
            $state = get_object_vars($state);
            array_walk($state["info"],
                function (&$el) {
                    $el = get_object_vars($el);
                }
            );
            usort($state["info"],
                function($a, $b) { return strcmp($a["location"], $b["location"]); }
            );
        }
    );
    

    【讨论】:

      【解决方案3】:

      改变这个

      foreach ($prop->children() as $stateattr)
      

      到这里

      foreach ($sortedStates as $stateattr)
      

      做到了。

      我可以发誓我已经试过了。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-08-05
        • 2015-05-11
        相关资源
        最近更新 更多