2009-08-27 26 views
6

Mam blok XSLT, które mogą być stosowane kilka razy w ciągu transformacji. Ale chcę, aby faktycznie działał tylko przy pierwszym użyciu, powinien zostać pominięty przez wszystkie subskrybujące czasy. Jak mam to zrobic?W XSLT, mogę uruchomić szablon tylko raz

Jako przykład, jest to rodzaj rzeczy chcę zrobić: W arkuszu stylów zdefiniować zmienną globalną:

<xsl:variable name="run_once" select="0"/> 

Następnie Mam szablon, który nazywa się kilka razy:

<xsl:template name="some_template"> 
    <xsl:if test="$run_once != 1"> 
     <xsl:variable name="run_once" select="1"/> 
     <xsl:text>THIS TEXT SHOULD APPEAR ONLY ONCE</xsl:text> 
    </xsl:if> 
</xsl:template> 

To nie działa, oczywiście, ponieważ zmienne nie mogą być zmienione, tylko przeciążone. Tak więc, gdy some_template wyjdzie z $ run_once będzie ponownie 0 i tekst zostanie zastosowany za każdym razem, gdy zostanie wywołany szablon. Czy istnieje jakiś typ funkcji ifdef lub inny obiekt globalny, który można ustawić?

Jeśli jesteś zainteresowany, dlaczego chcę to zrobić, poniżej znajduje się bardziej szczegółowe wyjaśnienie mojego problemu i rozwiązanie użyłem:

  • Mój wkład jest dane w surowym formacie XML, moje wyjście jest zgłoś w formacie WordML.
  • Na wejściu mam serię węzłów (o nazwie theNode). Niektóre, ale nie wszystkie, muszą być wyświetlane na wyjściu. Węzeł powinien być wyświetlany tylko wtedy, gdy prawda jest prawdziwa (hairyLogic jest oczywiście długi i kompleks).
  • theNode również mają typ (przechowywany w pod-węzeł). Na wejściu wszystkie węzły tego samego typu będą zawsze grupowane razem. Na wyjściu wszystkie węzły tego samego typu powinny być zgrupowane pod konkretnym nagłówkiem tego typu ( ) dla każdego typu powinien być tylko jeden nagłówek dla każdego typu ).

To rozwiązanie skończyło się przy użyciu:

... 
<xsl:apply-templates select="theNode[hairyLogic]"/> 
... 

<xsl:template match="theNode"> 
    <xsl:if test="count(preceding-sibling::theNode[type = current()/type and hairyLogic])=0"> 
     <xsl:choose> 
      <xsl:when test="type = 'TYPE1a' or type = 'TYPE1b'"> 
       <xsl:call-template name="TYPE1Heading"/> 
      </xsl:when> 
      <xsl:when test="type = 'TYPE2'"> 
       <xsl:call-template name="TYPE2Heading"/> 
      </xsl:when> 
     </xsl:choose> 
    </xsl:if> 
    ... 
</xsl:template> 

wybrałem używać nazwanych szablony dla nagłówków, ponieważ zawierają one podstawowe WordML, który nie zależy od żadnych danych w formacie XML wejściowego.

Nie podoba mi się to rozwiązanie, ponieważ hairyLogic jest powtarzany, a instrukcja if jest zawiła i trudna do odczytania. Może masz lepsze rozwiązanie, które nie wymaga zmiennych zmiennych?

Odpowiedz

2

Proponuję użyć szablonów dopasowań do nazwanych szablonów, ponieważ to więcej, cóż, jaki jest ekwiwalent XSLT dla pythonic? Xslt-y?Myślę, że przekonasz się, że możesz łatwiej rozwiązywać problemy w tej metodologii przetwarzania.

Jeśli nalegasz na używanie nazwanych szablonów z powodu pewnych nieznanych wymagań, może się okazać, że jeśli zmodyfikujesz swoją logikę, aby ułatwić wykrycie pierwszego wystąpienia, uprościsz całkowicie swoją logikę.

Czy możesz wyjaśnić, dlaczego nie możesz wykryć, kiedy pierwsza instancja jest potrzebna? Prawdopodobnie pomożemy stworzyć wyrażenie xpath, które pozwoliłoby ci na to, czego chcesz. Na przykład.

<xsl:template name="some_template"> 
    <xsl:variable name="EXPRESSION" select=".[somelogic='true']"/> 
    <xsl:if test="$EXPRESSION"> 
     <xsl:text>THIS TEXT SHOULD APPEAR ONLY ONCE</xsl:text> 
    </xsl:if> 
</xsl:template> 

Od XSLT jest deterministyczny - efekt jest całkowicie funkcjonalny jak Greg umieścić go - (chyba że robisz dziwne rzeczy przedłużacz) można zdecydować, kiedy po raz pierwszy jest to właściwe, stosując logikę do wejścia. Ponadto masz dostęp do węzła kontekstu w szablonie, dzięki czemu wiesz, skąd jest wywoływany.

+0

"co jest odpowiednikiem XSLT pythonic? Xslt-y?" - jest "deklaratywny" –

+0

Tak, mam ograniczenia, których nie szczegółowo opisałem (dodano do pytania, jeśli jesteś zainteresowany). Rozwiązałem problem tak, jak opisujesz. Nie podoba mi się to, ponieważ "somelogiczny" jest długi, niechlujny i teraz jest powtarzany kilka razy. Nie byłoby tak źle, gdybym mógł dyktować, kiedy kod XPATH jest analizowany, tak jak ja w innych językach funkcjonalnych. Wtedy mógłbym zapisać zły fragment "somelogiczny" w zmiennej i wstawić go w moje wyrażenia, gdy jest to potrzebne. – oillio

2

Ponieważ XSLT jest czysto funkcjonalnym językiem, istnieje nie zmiennych globalnych, które można ustawić.

Zamiast tego należy wybrać okoliczności, w których należy wywołać szablon some_template. Jeśli chcesz zadzwonić tylko raz, a następnie zadzwoń do niego tylko raz.