Reputation: 420
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?
Upvotes: 2
Views: 1936
Reputation: 558
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:
Upvotes: 0
Reputation: 96189
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.
Upvotes: 2
Reputation: 166
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;
}
Upvotes: 0