2

I'm trying to make a page using data from the discogs.com (XML)-API. i've been parsing it with simpleXML and it's working pretty well but there is some things i'm not sure how to do.

Here is part of the 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>

What i want to achieve is something similair to how discogs presents the releases: http://www.discogs.com/artist/Mics+Of+Fury where diferent versions of the same release are sorted together. (see. The M.O.F Blend in my link) This is done on discogs with having a master release that features the other releases. unfortunately this information isn't present in the API data, so i want to do the same thing by grouping the <release>-nodes with the same <title>-tags, or add a flag to the <releases> that don't have a unique <title>? any good ideas on the best way of doing this?

i also like to know if it's possible to count the <release>-nodes (child of releases) that have the same type-attribute? like in this example count the releases with the type "Main"?

maybe it's better to do this things with XMLReader or XPath?

3 Answers 3

2

You can use xsl(t) and php's XSLTProcessor.
In xslt 2.0 you could use something like

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

Unfortunately libxslt doesn't support this (at least the version used in the php.net win32 build of php 5.3.2 doesn't).
But you can use the Muenchian grouping method.

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 containing the xml document you provided.
And 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);

And the output (onlye the <table>-part) is:

<table border="1">
  <tr><th colspan="3">The M.O.F Blend</th></tr>
  <tr>
    <td>2002</td>
    <td>Blenda Records</td>
    <td>LP</td>
  </tr>
  <tr>
    <td>2002</td>
    <td>Blenda Records</td>
    <td>CD</td>
  </tr>
  <tr><th colspan="3">Versions</th></tr>
  <tr>
    <td>1999</td>
    <td>Not On Label</td>
    <td>12", EP</td>
  </tr>
  <tr><th colspan="3">Ännu En Gång Vol. 3</th></tr>
  <tr>
    <td>2001</td>
    <td>Hemmalaget</td>
    <td>Cass, Comp, Mix</td>
  </tr>
</table>

Now, that's not much of an explaination. But maybe it gives you some hints to what to search for.

Sign up to request clarification or add additional context in comments.

Comments

0

I have recently built a class I use for creating and sorting HTML tables of objects, here are a some static methods from it you may find useful for sorting associative arrays. I have removed the self:: reference so you can just use the methods as functions.

Usage: $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;
    }

Comments

0

I guess that xslt 2.0 may be able help you, here's the documentation for applying grouping and sorting on XML data using xsl 2.0:

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.