sorting my XML

PHP programming forum. Ask questions or help people concerning PHP code. Don't understand a function? Need help implementing a class? Don't understand a class? Here is where to ask. Remember to do your homework!

Moderator: General Moderators

Post Reply
mrivorey1
Forum Newbie
Posts: 4
Joined: Sun Aug 19, 2007 11:59 am

sorting my XML

Post by mrivorey1 »

feyd | Please use

Code: Select all

,

Code: Select all

and [syntax="..."] tags where appropriate when posting code. Your post has been edited to reflect how we'd like it posted. Please read:  [url=http://forums.devnetwork.net/viewtopic.php?t=21171]Posting Code in the Forums[/url] to learn how to do it too.[/color]


I have an XML file of members in a costuming organization.  I'd like to be able to sort this data variably sometimes on based on last name (with secondary sorting on first name), and other times based on member number (TKID, not USERID below).  The XML looks like this.

[syntax="xml"]

<?xml version="1.0" encoding="ISO-8859-1"?>
<?xml-stylesheet type="text/xsl" href="member_test.xsl"?>
<garrison>
     <members>
          <member>
              <first>John</first>
              <last>Doe</last>
              <tkid>100</tkid>
              <costume>TK</costume>
              <costume>BH</costume>
              <userid>2545</userid>
          </member>
          <member>
              <first>Joe</first>
              <last>Blow</last>
              <tkid>148</tkid>
              <costume>BH</costume>
              <costume>TK</costume>
              <costume>TB</costume>
              <userid>2612</userid>
          </member>
          <member>
              <first>Jane</first>
              <last>Doe</last>
              <tkid>101</tkid>
              <costume>TK</costume>
              <userid>2612</userid>
          </member>
   </members>
</garrison>


I'm using PHP4. Here is the code I'm using to parse.[/syntax]

Code: Select all

<?php
class xml_member{
    var $first, $last, $tkid, $userid;
    var $costume = array();
}
// this function handles each opening XML tag.  example: <costume>
function startTag($parser, $data){
    global $current_tag;
    $current_tag .= "*$data";
}
// this function handles each closing XML tag.  example: </costume>
function endTag($parser, $data){
    global $current_tag;
    $tag_key = strrpos($current_tag, '*');
    $current_tag = substr($current_tag, 0, $tag_key);
}
// this function handles the data between opening and closing tags.
function contents($parser, $data){
    global $current_tag, $xml_first_key, $xml_last_key, $xml_tkid_key, $xml_userid_key, $xml_costume_key, $counter, $member_array;
    switch($current_tag){
        case $xml_first_key:
            $member_array[$counter] = new xml_member();
            $member_array[$counter]->first = $data;
            break;
        case $xml_last_key:
            $member_array[$counter]->last = $data;
            break;
        case $xml_tkid_key:
            $member_array[$counter]->tkid = $data;
            break;
        case $xml_costume_key:
            $member_array[$counter]->costume[] = $data;
            break;
        case $xml_userid_key:
            $member_array[$counter]->userid = $data;
            $counter++;
            break;
    }
}


As you can see, the relevant data for, lets say the last name, end up in $member_array[$counter]->last


Can someone reply with code that will alternately sort $member_array based on last name (with secondary sort on first), and on TKID?


PS: Please forgive me if my code is crap, I'm still learning, and without proper instruction.


feyd | Please use

Code: Select all

,

Code: Select all

and [syntax="..."] tags where appropriate when posting code. Your post has been edited to reflect how we'd like it posted. Please read:  [url=http://forums.devnetwork.net/viewtopic.php?t=21171]Posting Code in the Forums[/url] to learn how to do it too.[/color]
User avatar
volka
DevNet Evangelist
Posts: 8391
Joined: Tue May 07, 2002 9:48 am
Location: Berlin, ger

Post by volka »

You can use xsl(t) to sort the xml data.
e.g. with php5's xls extension

Code: Select all

<?php
$xsl = new XSLTProcessor();
$xsl->importStyleSheet( DOMDocument::load('sort.xsl') );

$doc = DOMDocument::load('data.xml');
$xsl->setParameter('', 'sortBy', 'last');
echo $xsl->transformToXML($doc);

Code: Select all

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:param name="sortBy" select="'userid'"/>

<xsl:template match="* | @*">
  <xsl:copy><xsl:copy-of select="@*"/><xsl:apply-templates/></xsl:copy>
</xsl:template>

<xsl:template match="members">
  <xsl:apply-templates select="member">
    <xsl:sort select="*[name()=$sortBy]" order="ascending" />
  </xsl:apply-templates>
</xsl:template>

</xsl:stylesheet>
There's a similar extension for php4 called xslt
But the lifetime of php4 is nearing its end.
mrivorey1
Forum Newbie
Posts: 4
Joined: Sun Aug 19, 2007 11:59 am

Post by mrivorey1 »

volka wrote:There's a similar extension for php4 called xslt
But the lifetime of php4 is nearing its end.
Well the good news is, I just discovered my server has PHP5 as well. It's just not the default.

I'll give this a try.
mrivorey1
Forum Newbie
Posts: 4
Joined: Sun Aug 19, 2007 11:59 am

Post by mrivorey1 »

feyd | Please use

Code: Select all

,

Code: Select all

and [syntax="..."] tags where appropriate when posting code. Your post has been edited to reflect how we'd like it posted. Please read:  [url=http://forums.devnetwork.net/viewtopic.php?t=21171]Posting Code in the Forums[/url] to learn how to do it too.[/color]


[quote="volka"][syntax="xsl"]<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:param name="sortBy" select="'userid'"/>

<xsl:template match="* | @*">
  <xsl:copy><xsl:copy-of select="@*"/><xsl:apply-templates/></xsl:copy>
</xsl:template>

<xsl:template match="members">
  <xsl:apply-templates select="member">
    <xsl:sort select="*[name()=$sortBy]" order="ascending" />
  </xsl:apply-templates>
</xsl:template>

</xsl:stylesheet>
[/quote]

Well, it's getting me closer, but the XLS leaves out the MEMBERS element (not to be confused with MEMBER) in the transformed XML. And apparently I don't know enough about XPath to fix it.


I got this:

Code: Select all

<garrison>
     <member>
              <first>John</first>
              <last>Adams</last>
              <tkid>8000</tkid>
              <costume>TK</costume>
              <userid>7326</userid>
          </member><member>
              <first>Beverly</first>
              <last>Adams</last>
              <tkid>8001</tkid>
              <costume>ID</costume>
              <userid>7461</userid>
          </member><member>
              <first>Joe</first>
              <last>Aginon</last>
              <tkid>7000</tkid>
              <costume>TD</costume>
              <costume>TC</costume>
              <userid>4234</userid>
          </member>
</garrison>


I wanted this:

Code: Select all

<garrison>
     <members>
          <member>
              <first>John</first>
              <last>Adams</last>
              <tkid>8000</tkid>
              <costume>TK</costume>
              <userid>7326</userid>
          </member><member>
              <first>Beverly</first>
              <last>Adams</last>
              <tkid>8001</tkid>
              <costume>ID</costume>
              <userid>7461</userid>
          </member><member>
              <first>Joe</first>
              <last>Aginon</last>
              <tkid>7000</tkid>
              <costume>TD</costume>
              <costume>TC</costume>
              <userid>4234</userid>
          </member>
     </members>
</garrison>



feyd | Please use[/syntax]

Code: Select all

,

Code: Select all

and [syntax="..."] tags where appropriate when posting code. Your post has been edited to reflect how we'd like it posted. Please read:  [url=http://forums.devnetwork.net/viewtopic.php?t=21171]Posting Code in the Forums[/url] to learn how to do it too.[/color]
User avatar
volka
DevNet Evangelist
Posts: 8391
Joined: Tue May 07, 2002 9:48 am
Location: Berlin, ger

Post by volka »

fortunately that's easy to fix ;)

Code: Select all

<xsl:template match="members">
  <members>
    <xsl:apply-templates select="member">
      <xsl:sort select="*[name()=$sortBy]" order="ascending" />
    </xsl:apply-templates>
  </members>
</xsl:template>
mrivorey1
Forum Newbie
Posts: 4
Joined: Sun Aug 19, 2007 11:59 am

Post by mrivorey1 »

SWEET!!! It worked!!! I just don't have enough experience with XSL yet. The obvious fix didn't even occur to me.

Now I just need to figure out how to do a secondary sort on first names (to sort people in the same family).
User avatar
volka
DevNet Evangelist
Posts: 8391
Joined: Tue May 07, 2002 9:48 am
Location: Berlin, ger

Post by volka »

http://www.w3.org/TR/xslt#element-sort wrote:Sorting is specified by adding xsl:sort elements as children of an xsl:apply-templates or xsl:for-each element. The first xsl:sort child specifies the primary sort key, the second xsl:sort child specifies the secondary sort key and so on. When an xsl:apply-templates or xsl:for-each element has one or more xsl:sort children, then instead of processing the selected nodes in document order, it sorts the nodes according to the specified sort keys and then processes them in sorted order.

Code: Select all

<xsl:template match="members">
  <members>
    <xsl:apply-templates select="member">
      <xsl:sort select="*[name()='last']" order="ascending" />
      <xsl:sort select="*[name()='first']" order="ascending" />
    </xsl:apply-templates>
  </members>
</xsl:template>
Post Reply