Search:

CWIS Developers Documentation

  • Main Page
  • Classes
  • Files
  • File List
  • File Members

XMLParser.php

Go to the documentation of this file.
00001 <?PHP
00002 #
00003 #   FILE:  SPT--XMLParser.php
00004 #
00005 #   METHODS PROVIDED:
00006 #       XMLParser()
00007 #           - constructor
00008 #       SomeMethod($SomeParameter, $AnotherParameter)
00009 #           - short description of method
00010 #
00011 #   AUTHOR:  Edward Almasy
00012 #
00013 #   Part of the Scout Portal Toolkit
00014 #   Copyright 2005 Internet Scout Project
00015 #   http://scout.wisc.edu
00016 #
00017 
00018 class XMLParser {
00019 
00020     # ---- PUBLIC INTERFACE --------------------------------------------------
00021 
00022     # object constructor
00023     function XMLParser()
00024     {
00025         # set default debug output level
00026         $this->DebugLevel = 0;
00027 
00028         # create XML parser and tell it about our methods
00029         $this->Parser = xml_parser_create();
00030         xml_set_object($this->Parser, $this);
00031         xml_set_element_handler($this->Parser, "OpenTag", "CloseTag");
00032         xml_set_character_data_handler($this->Parser, "ReceiveData");
00033 
00034         # initialize tag storage arrays
00035         $this->TagNames = array();
00036         $this->TagAttribs = array();
00037         $this->TagData = array();
00038         $this->TagParents = array();
00039 
00040         # initialize indexes for parsing and retrieving data
00041         $this->CurrentParseIndex = -1;
00042         $this->CurrentSeekIndex = -1;
00043         $this->NameKeyCache = array();
00044     }
00045 
00046     # parse text stream and store result
00047     function ParseText($Text, $LastTextToParse = TRUE)
00048     {
00049         # pass text to PHP XML parser
00050         xml_parse($this->Parser, $Text, $LastTextToParse);
00051     }
00052 
00053     # move current tag pointer to specified item (returns NULL on failure)
00054     function SeekTo()    # (args may be tag names or indexes)
00055     {
00056         # perform seek based on arguments passed by caller
00057         $SeekResult = $this->PerformSeek(func_get_args(), TRUE);
00058 
00059         # if seek successful
00060         if ($SeekResult !== NULL)
00061         {
00062             # retrieve item count at seek location
00063             $ItemCount = count($this->CurrentItemList);
00064         }
00065         else
00066         {
00067             # return null value to indicate that seek failed
00068             $ItemCount = NULL;
00069         }
00070 
00071         # return count of tags found at requested location
00072         if ($this->DebugLevel > 0)
00073         {
00074             print("XMLParser->SeekTo(");
00075             $Sep = "";
00076             $DbugArgList = "";
00077             foreach (func_get_args() as $Arg)
00078             {
00079                 $DbugArgList .= $Sep."\"".$Arg."\"";
00080                 $Sep = ", ";
00081             }
00082             print($DbugArgList.") returned ".intval($ItemCount)." items starting at index ".$this->CurrentSeekIndex."\n");
00083         }
00084         return $ItemCount;
00085     }
00086 
00087     # move seek pointer up one level (returns tag name or NULL if no parent)
00088     function SeekToParent()
00089     {
00090         # if we are not at the root of the tree
00091         if ($this->CurrentSeekIndex >= 0)
00092         {
00093             # move up one level in tree
00094             $this->CurrentSeekIndex = $this->TagParents[$this->CurrentSeekIndex];
00095 
00096             # clear item list
00097             unset($this->CurrentItemList);
00098 
00099             # return name of new tag to caller
00100             $Result = $this->TagNames[$this->CurrentSeekIndex];
00101         }
00102         else
00103         {
00104             # return NULL indicating that no parent was found
00105             $Result = NULL;
00106         }
00107 
00108         # return result to caller
00109         if ($this->DebugLevel > 0) {  print("XMLParser->SeekToParent() returned ".$Result."<br>\n");  }
00110         return $Result;
00111     }
00112 
00113     # move seek pointer to first child of current tag (returns tag name or NULL if no children)
00114     function SeekToChild($ChildIndex = 0)
00115     {
00116         # look for tags with current tag as parent
00117         $ChildTags = array_keys($this->TagParents, $this->CurrentSeekIndex);
00118 
00119         # if child tag was found with requested index
00120         if (isset($ChildTags[$ChildIndex]))
00121         {
00122             # set current seek index to child
00123             $this->CurrentSeekIndex = $ChildTags[$ChildIndex];
00124 
00125             # clear item list info
00126             unset($this->CurrentItemList);
00127 
00128             # return name of new tag to caller
00129             $Result = $this->TagNames[$this->CurrentSeekIndex];
00130         }
00131         else
00132         {
00133             # return NULL indicating that no children were found
00134             $Result = NULL;
00135         }
00136 
00137         # return result to caller
00138         if ($this->DebugLevel > 0) {  print("XMLParser->SeekToChild() returned ".$Result."<br>\n");  }
00139         return $Result;
00140     }
00141 
00142     # move seek pointer to root of tree
00143     function SeekToRoot()
00144     {
00145         $this->CurrentSeekIndex = -1;
00146     }
00147 
00148     # move to next tag at current level (returns tag name or NULL if no next)
00149     function NextTag()
00150     {
00151         # get list of tags with same parent as this tag
00152         $LevelTags = array_keys($this->TagParents, 
00153                 $this->TagParents[$this->CurrentSeekIndex]);
00154 
00155         # find position of next tag in list
00156         $NextTagPosition = array_search($this->CurrentSeekIndex, $LevelTags) + 1;
00157 
00158         # if there is a next tag
00159         if (count($LevelTags) > $NextTagPosition)
00160         {
00161             # move seek pointer to next tag at this level
00162             $this->CurrentSeekIndex = $LevelTags[$NextTagPosition];
00163 
00164             # rebuild item list
00165 
00166             # return name of tag at new position to caller
00167             return $this->TagNames[$this->CurrentSeekIndex];
00168         }
00169         else
00170         {
00171             # return NULL to caller to indicate no next tag
00172             return NULL;
00173         }
00174     }
00175 
00176     # move to next instance of current tag (returns index or NULL if no next)
00177     function NextItem()
00178     {
00179         # set up item list if necessary
00180         if (!isset($this->CurrentItemList)) {  $this->RebuildItemList();  }
00181 
00182         # if there are items left to move to
00183         if ($this->CurrentItemIndex < ($this->CurrentItemCount - 1))
00184         {
00185             # move item pointer to next item
00186             $this->CurrentItemIndex++;
00187 
00188             # set current seek pointer to next item
00189             $this->CurrentSeekIndex = 
00190                     $this->CurrentItemList[$this->CurrentItemIndex];
00191 
00192             # return new item index to caller
00193             $Result = $this->CurrentItemIndex;
00194         }
00195         else
00196         {
00197             # return NULL value to caller to indicate failure
00198             $Result = NULL;
00199         }
00200 
00201         # return result to caller
00202         return $Result;
00203     }
00204 
00205     # move to previous instance of current tag (returns index or NULL on fail)
00206     function PreviousItem()
00207     {
00208         # set up item list if necessary
00209         if (!isset($this->CurrentItemList)) {  $this->RebuildItemList();  }
00210 
00211         # if we are not at the first item
00212         if ($this->CurrentItemIndex > 0)
00213         {
00214             # move item pointer to previous item
00215             $this->CurrentItemIndex--;
00216 
00217             # set current seek pointer to next item
00218             $this->CurrentSeekIndex = 
00219                     $this->CurrentItemList[$this->CurrentItemIndex];
00220 
00221             # return new item index to caller
00222             return $this->CurrentItemIndex;
00223         }
00224         else
00225         {
00226             # return NULL value to caller to indicate failure
00227             return NULL;
00228         }
00229     }
00230 
00231     # retrieve tag name from current seek point
00232     function GetTagName()
00233     {
00234         if (isset($this->TagNames[$this->CurrentSeekIndex]))
00235         {
00236             return $this->TagNames[$this->CurrentSeekIndex];
00237         }
00238         else
00239         {
00240             return NULL;
00241         }
00242     }
00243 
00244     # retrieve data from current seek point
00245     function GetData()
00246     {
00247         # assume that we will not be able to retrieve data
00248         $Data = NULL;
00249 
00250         # if arguments were supplied
00251         if (func_num_args())
00252         {
00253             # retrieve index for specified point
00254             $Index = $this->PerformSeek(func_get_args(), FALSE);
00255 
00256             # if valid index was found
00257             if ($Index !== NULL)
00258             {
00259                 # retrieve data at index to be returned to caller
00260                 $Data = $this->TagData[$Index];
00261             }
00262         }
00263         else
00264         {
00265             # if current seek index points to valid tag
00266             if ($this->CurrentSeekIndex >= 0)
00267             {
00268                 # retrieve data to be returned to caller
00269                 $Data = $this->TagData[$this->CurrentSeekIndex];
00270             }
00271         }
00272 
00273         # return data to caller
00274         if ($this->DebugLevel > 0)
00275         {  
00276             print("XMLParser->GetData(");
00277             if (func_num_args()) {  $ArgString = "";  foreach (func_get_args() as $Arg) {  $ArgString .= "\"".$Arg."\", ";  }  $ArgString = substr($ArgString, 0, strlen($ArgString) - 2);  print($ArgString);  }
00278             print(") returned ".($Data ? "\"".$Data."\"" : "NULL")."<br>\n");  
00279         }
00280         return $Data;
00281     }
00282 
00283     # retrieve specified attribute(s) from current seek point or specified point below
00284     #   (first arg is attribute name and optional subsequent args tell where to seek to)
00285     #   (returns NULL if no such attribute for current or specified tag)
00286     function GetAttribute()
00287     {
00288         # retrieve attribute
00289         $Args = func_get_args();
00290         $Attrib = $this->PerformGetAttribute($Args, FALSE);
00291 
00292         # return requested attribute to caller
00293         if ($this->DebugLevel > 0) {  print("XMLParser->GetAttribute() returned ".$Attrib."<br>\n");  }
00294         return $Attrib;
00295     }
00296     function GetAttributes()
00297     {
00298         # retrieve attribute
00299         $Args = func_get_args();
00300         $Attribs = $this->PerformGetAttribute($Args, TRUE);
00301 
00302         # return requested attribute to caller
00303         if ($this->DebugLevel > 0) {  print("XMLParser->GetAttributes() returned ".count($Attribs)." attributes<br>\n");  }
00304         return $Attribs;
00305     }
00306 
00307 
00308     # ---- PRIVATE INTERFACE -------------------------------------------------
00309 
00310     var $TagNames;
00311     var $TagAttribs;
00312     var $TagData;
00313     var $TagParents;
00314     var $CurrentParseIndex;
00315     var $CurrentSeekIndex;
00316     var $CurrentItemIndex;
00317     var $CurrentItemList;
00318     var $CurrentItemCount;
00319     var $DebugLevel;
00320     var $NameKeyCache;
00321     
00322     # set current debug output level (0-9)
00323     function SetDebugLevel($NewLevel)
00324     {
00325         $this->DebugLevel = $NewLevel;
00326     }
00327     
00328     # callback function for handling open tags
00329     function OpenTag($Parser, $ElementName, $ElementAttribs)
00330     {
00331         # add new tag to list
00332         $NewTagIndex = count($this->TagNames);
00333         $this->TagNames[$NewTagIndex] = $ElementName;
00334         $this->TagAttribs[$NewTagIndex] = $ElementAttribs;
00335         $this->TagParents[$NewTagIndex] = $this->CurrentParseIndex;
00336         $this->TagData[$NewTagIndex] = NULL;
00337 
00338         # set current tag to new tag
00339         $this->CurrentParseIndex = $NewTagIndex;
00340     }
00341     
00342     # callback function for receiving data between tags
00343     function ReceiveData($Parser, $Data)
00344     {
00345         # add data to currently open tag
00346         $this->TagData[$this->CurrentParseIndex] .= $Data;
00347     }
00348     
00349     # callback function for handling close tags
00350     function CloseTag($Parser, $ElementName)
00351     {
00352         # if we have an open tag and closing tag matches currently open tag
00353         if (($this->CurrentParseIndex >= 0)
00354                 && ($ElementName == $this->TagNames[$this->CurrentParseIndex]))
00355         {
00356             # set current tag to parent tag
00357             $this->CurrentParseIndex = $this->TagParents[$this->CurrentParseIndex];
00358         }
00359     }
00360 
00361     # perform seek to point in tag tree and update seek pointer (if requested)
00362     function PerformSeek($SeekArgs, $MoveSeekPointer)
00363     {
00364         # for each tag name or index in argument list
00365         $NewSeekIndex = $this->CurrentSeekIndex;
00366         foreach ($SeekArgs as $Arg)
00367         {
00368             # if argument is string
00369             if (is_string($Arg))
00370             {
00371                 # look for tags with given name and current tag as parent
00372                 $Arg = strtoupper($Arg);
00373                 if (!isset($this->NameKeyCache[$Arg]))
00374                 {
00375                     $this->NameKeyCache[$Arg] = array_keys($this->TagNames, $Arg);
00376                     $TestArray = array_keys($this->TagNames, $Arg);
00377                 }
00378                 $ChildTags = array_keys($this->TagParents, $NewSeekIndex);
00379                 $NewItemList = array_values(
00380                         array_intersect($this->NameKeyCache[$Arg], $ChildTags));
00381                 $NewItemCount = count($NewItemList);
00382 
00383                 # if matching tag found
00384                 if ($NewItemCount > 0)
00385                 {
00386                     # update local seek index
00387                     $NewSeekIndex = $NewItemList[0];
00388 
00389                     # save new item index
00390                     $NewItemIndex = 0;
00391                 }
00392                 else
00393                 {
00394                     # report seek failure to caller
00395                     return NULL;
00396                 }
00397             }
00398             else
00399             {
00400                 # look for tags with same name and same parent as current tag
00401                 $NameTags = array_keys($this->TagNames, $this->TagNames[$NewSeekIndex]);
00402                 $ChildTags = array_keys($this->TagParents, $this->TagParents[$NewSeekIndex]);
00403                 $NewItemList = array_values(array_intersect($NameTags, $ChildTags));
00404                 $NewItemCount = count($NewItemList);
00405 
00406                 # if enough matching tags were found to contain requested index
00407                 if ($NewItemCount > $Arg)
00408                 {
00409                     # update local seek index
00410                     $NewSeekIndex = $NewItemList[$Arg];
00411 
00412                     # save new item index
00413                     $NewItemIndex = $Arg;
00414                 }
00415                 else
00416                 {
00417                     # report seek failure to caller
00418                     return NULL;
00419                 }
00420             }
00421         }
00422 
00423         # if caller requested that seek pointer be moved to reflect seek
00424         if ($MoveSeekPointer)
00425         {
00426             # update seek index
00427             $this->CurrentSeekIndex = $NewSeekIndex;
00428 
00429             # update item index and list
00430             $this->CurrentItemIndex = $NewItemIndex;
00431             $this->CurrentItemList = $NewItemList;
00432             $this->CurrentItemCount = $NewItemCount;
00433         }
00434 
00435         # return index of found seek
00436         return $NewSeekIndex;
00437     }
00438 
00439     function PerformGetAttribute($Args, $GetMultiple)
00440     {
00441         # assume that we will not be able to retrieve attribute
00442         $ReturnVal = NULL;
00443 
00444         # retrieve attribute name and (possibly) seek arguments
00445         if (!$GetMultiple)
00446         {
00447             $AttribName = strtoupper(array_shift($Args));
00448         }
00449 
00450         # if arguments were supplied
00451         if (count($Args))
00452         {
00453             # retrieve index for specified point
00454             $Index = $this->PerformSeek($Args, FALSE);
00455 
00456             # if valid index was found
00457             if ($Index !== NULL)
00458             {
00459                 # if specified attribute exists
00460                 if (isset($this->TagAttribs[$Index][$AttribName]))
00461                 {
00462                     # retrieve attribute(s) at index to be returned to caller
00463                     if ($GetMultiple)
00464                     {
00465                         $ReturnVal = $this->TagAttribs[$Index];
00466                     }
00467                     else
00468                     {
00469                         $ReturnVal = $this->TagAttribs[$Index][$AttribName];
00470                     }
00471                 }
00472             }
00473         }
00474         else
00475         {
00476             # if current seek index points to valid tag
00477             if ($this->CurrentSeekIndex >= 0)
00478             {
00479                 # if specified attribute exists
00480                 if (isset($this->TagAttribs[$this->CurrentSeekIndex][$AttribName]))
00481                 {
00482                     # retrieve attribute(s) to be returned to caller
00483                     if ($GetMultiple)
00484                     {
00485                         $ReturnVal = $this->TagAttribs[$this->CurrentSeekIndex];
00486                     }
00487                     else
00488                     {
00489                         $ReturnVal = $this->TagAttribs[$this->CurrentSeekIndex][$AttribName];
00490                     }
00491                 }
00492             }
00493         }
00494 
00495         # return requested attribute to caller
00496         return $ReturnVal;
00497     }
00498 
00499     # rebuild internal list of tags with the same tag name and same parent as current
00500     function RebuildItemList()
00501     {
00502         # get list of tags with the same parent as current tag
00503         $SameParentTags = array_keys($this->TagParents, 
00504                 $this->TagParents[$this->CurrentSeekIndex]);
00505 
00506         # get list of tags with the same name as current tag
00507         $SameNameTags = array_keys($this->TagNames, 
00508                 $this->TagNames[$this->CurrentSeekIndex]);
00509 
00510         # intersect lists to get tags with both same name and same parent as current
00511         $this->CurrentItemList = array_values(
00512                 array_intersect($SameNameTags, $SameParentTags));
00513 
00514         # find and save index of current tag within item list
00515         $this->CurrentItemIndex = array_search(
00516                 $this->CurrentSeekIndex, $this->CurrentItemList);
00517 
00518         # save length of item list
00519         $this->CurrentItemCount = count($this->CurrentItemList);
00520     }
00521 
00522     # internal method for debugging
00523     function DumpInternalArrays()
00524     {
00525         foreach ($this->TagNames as $Index => $Name)
00526         {
00527             printf("[%03d] %-12.12s %03d %-30.30s \n", $Index, $Name, $this->TagParents[$Index], trim($this->TagData[$Index]));
00528         }
00529     }
00530 }
00531 
00532 
00533 ?>
CWIS logo doxygen
Copyright 2009 Internet Scout