Сортировать / группировать данные XML с помощью PHP? - PullRequest
2 голосов
/ 30 марта 2010

Я пытаюсь создать страницу, используя данные из discogs.com (XML) -API. я разбираю его с simpleXML, и он работает довольно хорошо, но есть некоторые вещи, которые я не знаю, как это сделать.

Вот часть XML:

<releases>
  <release id="1468764" status="Accepted" type="Main">
    <title>Versions</title>
    <format>12", EP</format>
    <label>Not On Label</label>
    <year>1999</year>
  </release>
  <release id="72246" status="Accepted" type="Main">
    <title>The M.O.F Blend</title>
    <format>LP</format>
    <label>Blenda Records</label>
    <year>2002</year>
  </release>
  <release id="890064" status="Accepted" type="Main">
    <title>The M.O.F Blend</title>
    <format>CD</format>
    <label>Blenda Records</label>
    <year>2002</year>
  </release>
  <release id="1563561" status="Accepted" type="TrackAppearance">
    <title>Ännu En Gång Vol. 3</title>
    <trackinfo>Backtrack</trackinfo>
    <format>Cass, Comp, Mix</format>
    <label>Hemmalaget</label>
    <year>2001</year>
  </release>
</releases>

То, чего я хочу достичь, похоже на то, как Discogs представляет релизы: http://www.discogs.com/artist/Mics+Of+Fury, где разные версии одного и того же выпуска сортируются вместе. (см. «Смесь М.О.Ф» в моей ссылке). Это делается на дисках с наличием мастер-релиза с другими релизами. к сожалению, эта информация отсутствует в данных API, поэтому я хочу сделать то же самое, сгруппировав узлы <release> с одинаковыми тегами <title>, или добавив флаг в <releases>, который не есть уникальный <title>? какие-нибудь хорошие идеи о наилучшем способе сделать это?

Мне также хотелось бы знать, возможно ли сосчитать <release> -узлы (потомки выпусков), которые имеют один и тот же атрибут типа? как в этом примере считать выпуски с типом «Main»?

может быть, лучше сделать это с XMLReader или XPath?

Ответы [ 3 ]

2 голосов
/ 03 апреля 2010

Вы можете использовать xsl (t) и XPLProcessor php .
В xslt 2.0 вы можете использовать что-то вроде

<xsl:for-each-group select="release" group-by="title">

К сожалению libxslt не поддерживает это (по крайней мере, версия, используемая в сборке php.net win32 php 5.3.2, не поддерживает).
Но вы можете использовать метод группировки Мюнхена .

test.xsl:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" version="4.0" encoding="utf-8" indent="yes"/>

<xsl:key name="release-by-title" match="release" use="title" />

<xsl:template match="/">
  <html>
    <head><title>...</title></head>
    <body>
      <xsl:apply-templates />
    </body>
  </html>
</xsl:template>

<xsl:template match="releases">
  <table border="1">
    <xsl:for-each select="release[count(. | key('release-by-title', title)[1]) = 1]">
      <xsl:sort select="title" />
      <tr>
        <th colspan="3"><xsl:value-of select="title" /></th>
      </tr>
      <xsl:for-each select="key('release-by-title', title)">
        <xsl:sort select="year" />
        <tr>
          <td><xsl:value-of select="year" /></td>
          <td><xsl:value-of select="label" /></td>
          <td><xsl:value-of select="format" /></td>
        </tr>
      </xsl:for-each>
    </xsl:for-each>
  </table>
</xsl:template>

</xsl:stylesheet>

test.xml, содержащий предоставленный вами документ xml.
И test.php:

<?php
$doc = new DOMDocument;
$doc->load('test.xsl');
$stylesheet = new XSLTProcessor;
$stylesheet->importStyleSheet($doc);
$doc->load('test.xml');

header('Content-type: text/html; charset=utf-8');
echo $stylesheet->transformToXML($doc);

И вывод (только

0 голосов
/ 28 октября 2010

Полагаю, что xslt 2.0 может помочь вам, вот документация по применению группировки и сортировки данных XML с использованием xsl 2.0:

0 голосов
/ 31 марта 2010

Я недавно создал класс, который я использую для создания и сортировки HTML-таблиц объектов, вот несколько статических методов, которые вы можете найти полезными для сортировки ассоциативных массивов. Я удалил self :: reference, чтобы вы могли просто использовать методы как функции.

Использование: $array = array_sort($array, 'sort_key_name');

function array_sort(&$array)
    {
        if(!$array) return $keys;
        $keys = func_get_args();
        array_shift($keys);
        array_sort_func($keys);
        usort($array,array("listview","array_sort_func"));
        return $array;
    }


function array_sort_func($a, $b = NULL)
    {
        static $keys;
        if($b === NULL) return $keys = $a;

        foreach($keys as $k)
        {
            $aval = hod($a, '$a->' . $k);
            $bval = hod($b, '$b->' . $k);

            // modify string to compate
            if(!is_numeric($aval)){$aval = strtolower($aval);}
            if(!is_numeric($bval)){$bval = strtolower($bval);}

            if($k[0]=='!')
            {
                $k=substr($k,1);

                if($aval!== $bval)
                {
                    if(is_numeric($aval) and is_numeric($bval))
                    {
                        return $aval - $bval;
                    }
                    else
                    {
                        return strcmp($bval, $aval);
                    }
                }
            }
            else if($aval !== $bval)
            {
                if(is_numeric($aval) and is_numeric($bval))
                {
                    $compare = $aval - $bval;

                    if($compare > 0)
                    {
                        return 1;
                    }
                    elseif($comare < 0)
                    {
                        return -1;
                    }
                }
                else
                {
                    return strcmp($aval, $bval);
                }
            }
        }

        return 0;
    }

function hod(&$base, $path)
    {
        $licz = '';
        $keys = explode("->", $path);
        $keys[0] = str_replace('$', '', $keys[0]);
        $expression = '$ret = ';
        $expression.= '$';

        foreach ($keys as $key)
        {
            if (++$licz == 1)
            {
                $expression.= 'base->';
            }
            else
            {
                $expression.= $key.'->';
            }
        }

        $expression = substr($expression, 0, -2);
        $expression.= ';';
        eval($expression);
        return $ret;
    }
...