2010-01-22 48 views
7

Tôi đã đọc những gì tôi đã tìm thấy trên Stackoverflow và vẫn chưa rõ về điều này.Sắp xếp một mảng các đối tượng SimpleXML

Tôi có một mảng của các đối tượng SimpleXML một cái gì đó như thế này:

array(2) { 
    [0]=> 
    object(SimpleXMLElement)#2 (2) { 
    ["name"]=> 
    string(15) "Andrew" 
    ["age"]=> 
    string(2) "21" 
    } 
    [1]=> 
    object(SimpleXMLElement)#3 (2) { 
    ["name"]=> 
    string(12) "Beth" 
    ["age"]=> 
    string(2) "56" 
    } 
} 

Và tôi muốn để có thể sắp xếp theo cột bất cứ điều gì, tăng dần hoặc giảm dần. Một cái gì đó như:

sort($data, 'name', 'asc'); 

Tôi có thể chuyển vào mảng đối tượng trên và sắp xếp theo giá trị của bất kỳ khóa nào tôi thích.

Để tham khảo, một giải pháp NET tương tự sẽ được cùng những dòng này: người

XmlSortOrder order = XmlSortOrder.Ascending; 
    if (sortDirection == "asc") { 
     order = XmlSortOrder.Ascending; 
    } 
    expression.AddSort(columnSortingOn + "/text()", order, 
     XmlCaseOrder.UpperFirst, "en-us", XmlDataType.Text); 

Tôi đã nhìn thấy nói

"Use usort"

Tiếp theo là một ví dụ cơ bản từ cuốn hướng dẫn PHP nhưng doesn này 't thực sự giải thích nó. Ít nhất là không phải với tôi. Tôi cũng đã thấy mọi người đề nghị sử dụng một thư viện bên ngoài như SimpleDOM nhưng tôi muốn tránh sử dụng một cái gì đó bên ngoài cho điều này (dường như, mặc dù tôi chưa thể giải quyết nó) điều nhỏ nhặt.

Bất kỳ trợ giúp nào được đánh giá cao, Cảm ơn!

Trả lời

3

Tôi đoán những người đề xuất sử dụng SimpleDOM sẽ là tôi. :)

Tôi đã viết SimpleDOM :: sort() chính xác cho trường hợp đó, bởi vì để sắp xếp SimpleXMLElements theo biểu thức trọng tài (hoặc biểu thức tùy ý), bạn cần sử dụng array_multisort(). bất cứ điều gì hữu ích.

Đây là phiên bản ngắn gọn về cách hoạt động: trước tiên bạn tạo một mảng proxy của các cặp khóa => giá trị tương ứng với mỗi SimpleXMLElement và giá trị mà chúng sẽ được sắp xếp. Trong ví dụ của bạn, nếu bạn muốn sắp xếp chúng theo <age/>, mảng sẽ là array(21, 56). Sau đó, bạn gọi array_multisort() với "mảng proxy" làm đối số đầu tiên, theo sau là bất kỳ số nào là sorting modifiers chẳng hạn như SORT_DESC hoặc SORT_NUMERIC sau đó cuối cùng là mảng bạn muốn sắp xếp, sẽ được chuyển theo tham chiếu.

Bạn sẽ kết thúc với một cái gì đó như thế:

$nodes = array(
    new SimpleXMLElement('<person><name>Andrew</name><age>21</age></person>'), 
    new SimpleXMLElement('<person><name>Beth</name><age>56</age></person>') 
); 

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

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

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

xsort($nodes, 'name', SORT_ASC); 
print_r($nodes); 

xsort($nodes, 'age', SORT_DESC); 
print_r($nodes); 

Nhưng thực sự, thay vì gánh nặng cho mình với mã hơn bạn sẽ phải duy trì và có thể kết thúc viết lại array_multisort() trong userspace, bạn nên tận dụng các giải pháp hiện có . Không có gì thú vị trong thuật toán/thường trình sắp xếp như vậy, thời gian của bạn sẽ tốt hơn cho một thứ không tồn tại.

+0

Vâng heck Josh, bạn kiên trì! Tôi cho rằng tôi sẽ thử nó vì nó sẽ cho phép tôi chuyển sang khối vấp ngã tiếp theo và tôi có thể sử dụng nó ở những nơi khác trong dự án này. – Stuart

+0

Tôi không nhất quán, chỉ nhất quán trong việc ủng hộ việc sử dụng lại mã. Nếu đoạn trích tôi đăng ở trên hoạt động cho bạn thì tất cả có nghĩa là hãy sử dụng đoạn mã đó. Hoặc sử dụng đóng cửa nếu bạn thích, bất cứ điều gì làm việc cho bạn. Như bạn đã nói, mục tiêu của bạn là tìm một giải pháp cho phép bạn chuyển sang khối vấp ngã tiếp theo và sẽ không yêu cầu bạn quay lại sau. –

+0

Điều đó "dai dẳng" có nghĩa là được miễn phí. Tôi được bán trên SimpleDOM. Nó chỉ hoạt động. Nhanh. Tuyệt vời, Josh. – Stuart

2

Tôi đã sẵn sàng giới thiệu usort() cho đến khi tôi nhận ra bạn đã đánh bại tôi với nó. Kể từ khi các ví dụ mã đã không được thực hiện tốt trong quá khứ, tôi sẽ cố gắng giải thích nó bằng tiếng Anh đơn giản và hy vọng rằng nó sẽ giúp bạn chỉ đúng hướng.

Bằng cách sử dụng usort(), bạn tạo "thuật toán" do người dùng tạo riêng. Hàm usort() gọi hàm so sánh của riêng bạn để xác định cách mỗi đối tượng của bạn liên quan đến nhau. Khi viết hàm so sánh của bạn, bạn sẽ nhận được thông qua trong hai đối tượng trong mảng của bạn. Với hai đối tượng đó, bạn trả lại kết quả về cơ bản cho biết usort() đối tượng đầu tiên là đối tượng thứ nhất là LESS THAN, EQUAL TO hoặc GREATER THAN. Bạn làm điều này bằng cách trả về -1, 0 hoặc 1 (tương ứng). Đó là nó. Bạn chỉ phải quan tâm đến việc hai đối tượng so sánh với nhau như thế nào và cơ chế phân loại thực tế được xử lý bởi usort() cho bạn.

Ok, bây giờ cho một ví dụ bán thực tế:

function myCompare($obj1, $obj2) { 
    if($obj1->someInt == $obj2->someInt) { 
     return 0; // equal to 
    } else if($obj1->someInt < $obj2->someInt) { 
     return -1; // less than 
    } else { 
     return 1; // greater than 
    } 
} 

$myArray = {a collection of your objects}; 

usort($myArray, 'myCompare'); 

này là khá nhiều ví dụ trong hướng dẫn sử dụng PHP, nhưng hy vọng nó có ý nghĩa trong bối cảnh hiện nay. Hãy cho tôi biết nếu tôi không rõ ràng về điều gì đó.

+0

vấn đề duy nhất với điều này là anh ta cần phải thực hiện các chức năng rõ ràng cho mỗi tài sản bởi vì anh ấy muốn có thể sắp xếp chúng theo bất kỳ giá trị phần tử xml nào có thể. Vì vậy, ông cần phải đến với một trung gian mà sẽ làm cho nó có thể sử dụng một tài sản và trật tự cung cấp tại thời gian gọi. – prodigitalson

+0

Bạn có thể sử dụng biến toàn cục để chỉ định cột nào sẽ được sử dụng trong so sánh (lưu ý các loại dữ liệu để so sánh giữa các chuỗi và số).Tôi không bao giờ thực sự khuyên bạn nên sử dụng một số globals mặc dù, vì vậy lý tưởng hơn, thực hiện điều này trong một lớp và sử dụng một biến thành viên để xác định cột. Tôi đã không bao giờ sử dụng 'usort()' theo cách này mặc dù, vì vậy tôi không thể hứa nó sẽ làm việc. Tôi sẽ chạy một bài kiểm tra nhanh nếu tôi có nhiều thời gian hơn. –

+1

Id nói gói nó lên trong một lớp là trung gian lý tưởng. Có lẽ bằng cách mở rộng ArrayObject. – prodigitalson

4

Các usort chức năng cho phép bạn nói với PHP

Hey, you! Sort this array I'm giving you with this function I wrote.

Nó không có gì đặc biệt để làm với SimpleXML. Đó là một chức năng chung để phân loại bộ sưu tập dữ liệu mảng dựng sẵn PHP.

Bạn cần viết hàm, phương pháp mẫu hoặc phương pháp tĩnh để sắp xếp mảng. Đối số thứ hai để usort chấp nhận một PHP Callback, là một loại giả cho phép bạn chỉ định hàm, phương thức cá thể hoặc phương thức tĩnh nào.

Hàm bạn viết sẽ chấp nhận hai đối số.Đây sẽ là hai giá trị khác nhau từ mảng của bạn

function cmp($a, $b) 
{ 
      if ($a == $b) { 
       return 0; 
      } 
      if($a < $b) { 
       return -1; 
      } 
      if($a > $b) { 
       return 1; 
      } 
} 

Bạn cần viết hàm này để trả về một trong ba giá trị.

If $a == $b, return 0 
If $a > $b, return -1 
if $a > $v, return 1 

Khi bạn gọi usort, PHP sẽ chạy qua mảng của bạn, gọi sắp xếp chức năng/phương pháp của bạn (trong trường hợp này cmp lặp đi lặp lại cho đến khi mảng được sắp xếp. Trong ví dụ của bạn, $ a và sẽ $ b .. được đối tượng SimpleXML

1

Dưới đây là một ví dụ khác của việc sử dụng usort() Cái này cho phép bạn chỉ định các biến đối tượng và sự chỉ đạo sắp xếp:

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

mã kiểm tra;

01.
class TestClass 
{ 
    public $name; 
    public $age; 

    public function __construct($name, $age) 
    { 
     $this->name = $name; 
     $this->age = $age; 
    } 
} 

$test[] = new TestClass('Tom', 28); 
$test[] = new TestClass('Mary', 48); 
$test[] = new TestClass('Beth', 38); 
$test[] = new TestClass('Cindy', 18); 
$test[] = new TestClass('Sid', 58); 
$test[] = new TestClass('Mandy', 8); 

$field = 'age'; 
$direction = SORT_DESC; 
sort_obj_arr($test, $field, $direction); 

echo '<pre>'; 
print_r($test); 
echo '</pre>'; 
+0

Tại sao $ sort_func = function ($ obj_1, $ obj_2) sử dụng ($ sort_field, $ sort_direction) cho tôi một lỗi cú pháp? – sloga

2

Josh Davis' giải pháp dường như không làm việc khi tải một file XML qua:

$nodes = simplexml_load_file('/home/usr/public_html/feeds/deadlines.php'); 

tôi nhận được lỗi sau:

Warning: array_multisort() [function.array-multisort]: Argument #3 is expected to be an array or a sort flag in /home/usr/public_html/feeds/deadlines.php on line 8

Nó liên quan đến: array_multisort ($ sort_proxy, $ order, $ nodes);

+0

xpath là cần thiết khi tải XML qua simplexml_load_file(). Xem http://stackoverflow.com/questions/3998722/how-to-sort-a-multi-dimensional-xml-file –

1

đó là một chủ đề cũ nhưng đây là giải pháp của tôi rằng một sử dụng để trích xuất thông tin từ một nguồn cấp rss để sắp xếp theo tiêu đề

$xml = simplexml_load_file('rss.xml'); 
$msg = array(); 
$msg_count = $xml->channel->item->count(); 

for ($x=0;$x<$msg_count;$x++){ 
    $msg[$x]['titl'] = (string)$xml->channel->item[$x]->title; 
    $msg[$x]['link'] = (string)$xml->channel->item[$x]->link; 
    $msg[$x]['date'] = (string)$xml->channel->item[$x]->pubDate; 
    $msg[$x]['time'] = strtotime(substr((string)$xml->channel->item[$x]->pubDate,4)); 
    $msg[$x]['desc'] = (string)$xml->channel->item[$x]->description; 
    $msg[$x]['auth'] = (string)$xml->channel->item[$x]->author; 
} 

foreach ($msg as $key => $row) { 
    $titl[$key] = $row['titl']; 
    $link[$key] = $row['link']; 
    $pdat[$key] = $row['date']; 
    $time[$key] = $row['time']; 
    $cate[$key] = $row['cate']; 
    $desc[$key] = $row['desc']; 
    $auth[$key] = $row['auth']; 
} 

array_multisort(
//change $titl to any variable created by "foreach" 
    $titl, SORT_ASC,SORT_NATURAL | SORT_FLAG_CASE, 
    $msg); 
Các vấn đề liên quan