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.
Beispiel der Anwendung:
Die XML-Datei:
Des Weiteren wird "Pi" nicht gefunden, wenn es Teil eines Tag-Namen oder in einem Attribut vorkommt.
Siehe auch:
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())===0 && $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($searchResult, SORT_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.► Teig + Tomate - Spinat = Pizza
► u=2*r*pi
Des Weiteren wird "Pi" nicht gefunden, wenn es Teil eines Tag-Namen oder in einem Attribut vorkommt.
Siehe auch:
