2012-12-28 17 views
6

Ich versuche, diese zu analysieren, Daten wie:PHP: Parsen nur xml Namespaces

<vin:layout name="Page" xmlns:vin="http://www.example.com/vin"> 
    <header> 
     {someText} 
     <div> 
      <!-- some invalid xml code --> 
      <aas> 
      <nav class="main"> 
       <vin:show section="Menu" /> 
      </nav> 
     </div> 
    </header> 
</vin:layout> 

Wie kann ich Daten wie folgt analysieren in PHP?

Ich versuchte DOM, aber es funktioniert nicht, wegen der fehlerhaften Xml innerhalb des Root-Elements. Kann ich dem Parser sagen, dass der Namespace ohne Text vin ist?

+0

Sie sowieso eine Abhilfe benötigen. Da [load_invalid_xml] (http://stackoverflow.com/questions/2890120/php-processing-invalid-xml) nicht funktioniert, würde ich ein SGML-Toolkit oder vielleicht SimpleHtmlDom (string/regex-based) anstelle von libxml). Als schnelle Escape-Prozedur, verarbeiten Sie sie mit einer Regex vor, um die nicht namespaced Tags in XML-Text mit '= preg_replace (" # <(?! /? \ W +: \ w +). *?)> # Smix "," < zu konvertieren $ 1 > ", $ xml)'. (Dies ist ein Kommentar, um die typische SO-Flak für die Erwähnung zu vermeiden.) – mario

+0

Aus welchem ​​Grund möchten Sie dies analysieren, was Sie versuchen zu tun? – GreenRover

+0

Dies sind einige Arten von Tempalte-Dateien. Alle namespaced Tags repräsentieren Funktionsaufrufe. Also muss ich die namespaced Tags durch irgendeinen anderen Inhalt ersetzen (Text oder mehr namespaced Tags). Aber ich denke, der einzige Weg zu gehen ist mit Regex ... – dkoch

Antwort

1

Ich würde wahrscheinlich eine Art Tagsoup-Parser darauf werfen. Etwas, das dein Format lesen kann, das abgesehen davon Mängel ziemlich gut geschrieben sieht. Nichts, das textuell einem einfachen, auf regulärem Ausdruck basierenden Scanner im Weg stehen würde. Ich habe meine Tagsoup mit nur den vier Knotentypen aufgerufen, die du bekommen hast: Starttag, Endtag, Text und Kommentar. Für die Tags müssen Sie über ihren Tagname und den NamespacePrefix wissen. Es ist nur so ähnlich wie XML/HTML für den Komfort, aber in der Tat ist dies alles "rool your own", also nicht diese Begriffe auf irgendwelche Standards zu dehnen.

Eine Verwendung jeden Tag (beginnen oder enden) zu ändern, das nicht wie die Namespacepräfix haben könnte aussehen ($string enthält die Daten, die Sie in Ihrer Frage haben):

$scanner = new TagsoupIterator($string); 

$nsPrefix = 'vin'; 

foreach ($scanner as $node) { 
    $isTag = $node instanceof TagsoupTag; 
    $isOfNs = $isTag && $node->getTagNsPrefix() === $nsPrefix; 
    if ($isTag && !$isOfNs) { 
     $node = strtr($node, ['&' => '&amp;', '<' => '&lt;']); 
    } 
    echo $node; 
} 

Ausgang:

<vin:layout name="Page" xmlns:vin="http://www.example.com/vin"> 
    &lt;header> 
     {someText} 
     &lt;div> 
      <!-- some invalid xml code --> 
      &lt;aas> 
      &lt;nav class="main"> 
       <vin:show section="Menu" /> 
      &lt;/nav> 
     &lt;/div> 
    &lt;/header> 
</vin:layout> 

eine Nutzung alles zu extrahieren innerhalb einer bestimmten Tag eines Namespace aussehen könnte:

$scanner = new TagsoupIterator($string); 
$parser = new TagsoupForwardNavigator($scanner); 

$startTagWithNsPrefix = function ($namespace) { 

    return function (TagsoupNode $node) use ($namespace) { 

     /* @var $node TagsoupTag */ 
     return $node->getType() === Tagsoup::NODETYPE_STARTTAG 
      && $node->getTagNsPrefix() === $namespace; 
    }; 
}; 

$start = $parser->nextCondition($startTagWithNsPrefix('vin')); 
$tag = $start->getTagName(); 
$parser->next(); 
echo $html = implode($parser->getUntilEndTag($tag)); 

Ausgang:

<header> 
    {someText} 
    <div> 
     <!-- some invalid xml code --> 
     <aas> 
     <nav class="main"> 
      <vin:show section="Menu" /> 
     </nav> 
    </div> 
</header> 

Der nächste Teil ist, dass ein Teil der $string zu ersetzen. Als tagsoup Binäroffsets und Längen bietet, ist dies einfach (und ich Verknüpfung ein wenig schmutzig über SimpleXML):

$xml = substr($string, 0, $start->getEnd()) . substr($string, $parser->getOffset()); 
$doc = new SimpleXMLElement($xml); 
$doc[0] = $html; 
echo $doc->asXML(); 

Ausgang: auf dem Beton

<vin:layout xmlns:vin="http://www.example.com/vin" name="Page"> 
    &lt;header&gt; 
     {someText} 
     &lt;div&gt; 
      &lt;!-- some invalid xml code --&gt; 
      &lt;aas&gt; 
      &lt;nav class="main"&gt; 
       &lt;vin:show section="Menu" /&gt; 
      &lt;/nav&gt; 
     &lt;/div&gt; 
    &lt;/header&gt; 
</vin:layout> 

je nach Bedarf dies würde erfordern die Implementierung ändern . Zum Beispiel wird dieser nicht erlauben, die gleichen Tags ineinander zu stecken. Es wirft dich nicht raus, aber es geht nicht damit um. Keine Ahnung, wenn Sie diesen Fall haben, wenn ja, müssten Sie einige Öffnen/Schließen-Zähler hinzufügen, könnte die Navigator-Klasse problemlos dafür erweitert werden, sogar um zwei Arten von Endtag-Suchmethoden anzubieten.

Die hier genannten Beispiele werden unter Verwendung der tagsoup, die Sie in diesem Kern sehen: https://gist.github.com/4415105