2012-10-18 13 views
12

Zastanawiam się, czy i jak można zarejestrować funkcję przestrzeni użytkownika PHP za pomocą procesora XSLT, który może nie tylko pobrać tablicę węzłów, ale także ją zwrócić?Jak filtrować wybrany zestaw węzłów za pomocą funkcji PHP?

Teraz PHP narzeka na tablicy do konwersji łańcucha za pomocą wspólnego Setup:

function all_but_first(array $nodes) {   
    array_shift($nodes); 
    shuffle($nodes); 
    return $nodes; 
}; 

$proc = new XSLTProcessor(); 
$proc->registerPHPFunctions(); 
$proc->importStylesheet($xslDoc); 
$buffer = $proc->transformToXML($xmlDoc); 

XmlDocument ($xmlDoc) przekształcenie może być na przykład:

<p> 
    <name>Name-1</name> 
    <name>Name-2</name> 
    <name>Name-3</name> 
    <name>Name-4</name> 
</p> 

W arkuszu stylów To się nazywa tak:

<xsl:template name="listing"> 
    <xsl:apply-templates select="php:function('all_but_first', /p/name)"> 
    </xsl:apply-templates> 
</xsl:template> 

Ogłoszenie dotyczy t on następujący:

Wskazówka: Array do konwersji łańcucha

Nie rozumiem dlaczego, jeśli funkcja pobiera tablicę jako wejście nie jest w stanie zwrócić tablicę, jak również?

Byłem też wypróbowaniu innych „funkcja” nazwiska jak widziałem jest php:functionString ale próbowałem tak daleko (php:functionArray, php:functionSet i php:functionList) nie działa.

W podręczniku PHP napisałem, że mogę zwrócić kolejne elementy zawierające DOMDocument, jednak te elementy nie są już z oryginalnego dokumentu. To nie ma dla mnie większego sensu.

+1

Zrobiłem dłuższą badań na ten temat, a ja przyszedłem z tego samego rozwiązania jak stwierdzono w ostatnim zdaniu: trzeba by wrócić inną 'DOMDocument' z tej funkcji. Ale potem znowu robi się bzdurny, ponieważ właśnie wydostałem zwykły tekst i żadnych węzłów. ('' xsl: for-each' też nie pomogło) –

+0

@DanLee: Dzięki za opinię. Po prostu próbowałem z iteratorem, ale to też nie jest radość: * "Ostrzeżenie: Obiekt PHP nie może zostać przekonwertowany na łańcuch XPath" * - następnie [Zajrzałem do źródła] (http: //lxr.sweon. net/php/http/source/ext/dom/xpath.C# L222) i obsługuje on tylko obiekt będący instancją jakiegoś DomNode - tak więc nie udało się uzyskać wszystkich xpathów węzła, związać ich i zwrócić "prawdziwego" DomNodeList zarówno. To bałagan :) Prawdopodobnie warto zasugerować, aby w tym miejscu wykorzystać tablicę węzłów domyskowych jako wartość zwracaną. – hakre

+0

Połączyłem niewłaściwą bibliotekę, ale kod jest identyczny: http://lxr.sweon.net/php/http/source/ext/xsl/xsltprocessor.c#L331 – hakre

Odpowiedz

3

Coś, co działa na mnie, to zwrócić instancję DOMDocumentFragment zamiast tablicy. Aby wypróbować to na twoim przykładzie, zapisałem twoje dane wejściowe jako . Potem zrobiłem foo.xslt wyglądać następująco:

<xsl:stylesheet version="1.0" xmlns:xsl='http://www.w3.org/1999/XSL/Transform' 
     xmlns:php="http://php.net/xsl"> 
    <xsl:template match="/"> 
     <xsl:call-template name="listing" /> 
    </xsl:template> 
    <xsl:template match="name"> 
     <bar> <xsl:value-of select="text()" /> </bar> 
    </xsl:template> 
    <xsl:template name="listing"> 
     <foo> 
      <xsl:for-each select="php:function('all_but_first', /p/name)"> 
       <xsl:apply-templates /> 
      </xsl:for-each> 
     </foo> 
    </xsl:template> 
</xsl:stylesheet> 

(. Jest to głównie właśnie Twój przykład z xsl:stylesheet owijki, aby go powołać) i prawdziwe sedno sprawy, foo.php:

<?php 

function all_but_first($nodes) { 
    if (($nodes == null) || (count($nodes) == 0)) { 
     return ''; // Not sure what the right "nothing" return value is 
    } 
    $returnValue = $nodes[0]->ownerDocument->createDocumentFragment(); 
    array_shift($nodes); 
    shuffle($nodes); 
    foreach ($nodes as $node) { 
     $returnValue->appendChild($node); 
    } 
    return $returnValue; 
}; 

$xslDoc = new SimpleXMLElement('./foo.xslt', 0, true); 
$xmlDoc = new SimpleXMLElement('./foo.xml', 0, true); 

$proc = new XSLTProcessor(); 
$proc->registerPHPFunctions(); 
$proc->importStylesheet($xslDoc); 
$buffer = $proc->transformToXML($xmlDoc); 
echo $buffer; 

?> 

Ważną część to wywołanie do ownerDocument->createDocumentFragment(), aby obiekt, który zostanie zwrócony z funkcji.

+0

Nie wiedziałem o twojej odpowiedzi, aż do teraz. Dziękuję bardzo, to naprawdę działa :) - Świetnie! – hakre