XML-Datei durchsuchen

September 2009

Mit diesem PHP-Skript kann man leicht ein XML-Dokument nach einem Begriff durchsuchen.
Dazu wird hier mit SimpleXML ein XML-Objekt der Datei erzeugt, welches dann mit dem Stichwort und anderen Parametern an die Funktion übergeben wird.
Der Rückgabewert der Funktion, ein Array, enthält die xPaths zu den gefundenen Knoten im Key und deren Relevanz im Wert.
Somit lassen sich die Resultate z.B. nach Relevanz sortieren und beliebig formatieren.

<?php
/*
@param  object(SimpleXMLElement) $xmlobj # das zu durchsuchende Objekt
@param  string  $searchValue # der zu suchende String
@param  array   $searchNodes # die zu durchsuchenden Tags, oder leer für alle Tags
@param  boolean $caseSensitive # Gross-/Kleinschreibung beachten
@return array   $xpaths # key = xPath zum Knoten, value = Anzahl Vorkommen von $searchValue
*/
function xmlSearch($xmlobj$searchValue$searchNodes=array(), $caseSensitive=false){
  
$node $xmlobj;
  
$nodeName $node->getName(); // Node-Name
  
$nodeAttrs $node->attributes(); // Node-Attribute
  
var_dump($nodeAttrs[0]);
  
$xpaths = array(); // xPath => Relevanz (@return)
  
if(count($nodeAttrs)!==0){ // Attribute sammeln ...
    
$nodeAttr = array();
    foreach(
$nodeAttrs as $a => $v)
      
$nodeAttr[] = '@'.$a.'="'.$v.'"'// ... und als xPath-String darstellen
    
$nodeAttr '['.implode(' and '$nodeAttr).']';
  }
  else 
// wenn keine Attribute
    
$nodeAttr '';
  
$relevance = ($caseSensitive// nach $searchValue suchen
        
substr_count((string)$node$searchValue)
        : 
preg_match_all('#'.preg_quote($searchValue'#').'#i', (string)$node$tmp);
  if(
count($node->children())===&& $relevance// keine Children und kein relevanter Text
    
$xpaths['/'.$nodeName.$nodeAttr] = $relevance// xPath hinzufügen
  
foreach($node as $child){ // Children auslesen
    
if(!in_array($child->getName(),$searchNodes) && $searchNodes!=array()
       && 
count($child->children())===0)
      continue; 
// irrelevantes Child ohne Grandchildren überspringen
    // Children auf Text oder Grandchildren überprüfen
    
$subResult xmlSearch($child$searchValue$searchNodes$caseSensitive);
    foreach(
$subResult as $xpathpart => $relevance)
      
$xpaths['/'.$nodeName.$nodeAttr.$xpathpart] = $relevance;
  }
  return 
$xpaths;
}
?>

Beispiel der Anwendung:
Die XML-Datei:
<?xml version="1.0"?>
<collection>
  <math id="7">u=2*r*pi</math>
  <lang id="2">Alpha, Delta, Pi, Omega</lang>
  <nonsense>
    <math>Teig + Tomate - Spinat = Pizza</math>
  </nonsense>
</collection>
Das Skript:
<?php
# XML-Datei oder -String laden
$xmlobj simplexml_load_file('zu-durchsuchende-datei.xml');

# Suche durchführen
$searchResult xmlSearch($xmlobj'Pi', array('math'), false);
/* $searchResult enthält:
   ['/collection/math[@id="7"]'] => 1
   ['/collection/nonsense/math'] => 2 */

# nach Relevanz absteigend sortieren
arsort($searchResultSORT_NUMERIC);

# Resultate zählen
printf('%s Übereinstimmungen in %s Knoten:',
        
array_sum($searchResult), count($searchResult));

# nur xPaths im Array
$xpaths array_keys($searchResult);
/* $xpaths enthält:
   [0] => '/collection/nonsense/math'
   [1] => '/collection/math[@id="7"]' */

# Suchresultat ausgeben
foreach($xpaths as $xpath){
  
$result $xmlobj->xpath($xpath);
  echo 
'► '.$result[0]."\r\n";
}
?>
Mögliche Ausgabe:
3 Übereinstimmungen in 2 Knoten:
► Teig + Tomate - Spinat = Pizza
► u=2*r*pi
Da in diesem Beispiel nur in <math>-Knoten gesucht wird, taucht das "Pi" vom <lang>-Knoten nicht im Suchresultat auf.

Des Weiteren wird "Pi" nicht gefunden, wenn es Teil eines Tag-Namen oder in einem Attribut vorkommt.

Siehe auch:
 


Andere Einträge