2012-06-04 6 views
2

Я застрял, узнав, как я могу получить доступ к текущему узлу, итерации по набору узлов с помощью xsL:for-each. Это мой XML:Доступ к текущему узлу в предикате с xsl: for-each

<events> 
    <event> 
     <date> 
      <year>2012</year> 
      <month>July</month> 
     </date> 
     <description>...</description> 
    </event> 
    <!-- more events --> 
</events> 

То, что я пытаюсь достичь является HTML-представление, как это:

<h2>2012</h2> 
<dl> 
    <dt>July</dt> 
    <dd>One of these for every event with year=2012 and month=July</dd> 

    <dt>August</dt> 
    <!-- ... --> 
</dl> 
<h2>2013</h2> 
<!-- ... --> 

Я использую XPath-выражение, чтобы получить все различные годы, а затем перебрать их вызывая шаблон с именем year с параметрами $year и $events. Получение значения для $year легко, но я изо всех сил стараюсь найти правильные события. Следующие действия не будут работать, вероятно, потому, что . во втором предикате относится к event, проверенному для предиката. Но как получить доступ к year?

<xsl:template match="events"> 
<xsl:for-each select="event[not(date/year=preceding-sibling::event/date/year)]/date/year"> 
<xsl:call-template name="year"> 
    <xsl:with-param name="year" select="." /> 
    <xsl:with-param name="events" select="event[date/year=.]" /> 
</xsl:call-template> 
</xsl:for-each> 
</xsl:template> 

Большое спасибо заранее!

PS: Должен работать с XPath и XSLT 1.0.

ответ

2

Это преобразование:

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
<xsl:output omit-xml-declaration="yes" indent="yes"/> 
<xsl:strip-space elements="*"/> 

<xsl:key name="kYear" match="year" use="."/> 

<xsl:key name="kEventByMonthYear" match="event" 
    use="string(date)"/> 

<xsl:key name="kMonthByMonthYear" match="month" 
    use="string(..)"/> 

<xsl:key name="kMonthByYear" match="month" 
use="../year"/> 

<xsl:template match="/*"> 
    <xsl:for-each select= 
    "*/date/year 
      [generate-id() = generate-id(key('kYear', .)[1])] 
    "> 
    <h2><xsl:value-of select="."/></h2> 
    <dl> 
     <xsl:apply-templates select= 
     "key('kMonthByYear', current()) 
      [generate-id() 
      = 
      generate-id(key('kMonthByMonthYear', 
          string(..) 
         )[1] 
        ) 
      ]"/> 
     </dl> 
    </xsl:for-each> 
</xsl:template> 

<xsl:template match="month"> 
    <dt><xsl:value-of select="."/></dt> 

    <xsl:for-each select= 
    "key('kEventByMonthYear', string(current()/..))"> 
    <dd><xsl:value-of select="description"/></dd> 
    </xsl:for-each> 
</xsl:template> 
</xsl:stylesheet> 

при нанесении на следующий документ XML:

<events> 
    <event> 
     <date> 
      <year>2012</year> 
      <month>January</month> 
     </date> 
     <description>Jan1</description> 
    </event> 
    <event> 
     <date> 
      <year>2012</year> 
      <month>January</month> 
     </date> 
     <description>Jan2</description> 
    </event> 
    <event> 
     <date> 
      <year>2012</year> 
      <month>March</month> 
     </date> 
     <description>Mar1</description> 
    </event> 
    <event> 
     <date> 
      <year>2012</year> 
      <month>March</month> 
     </date> 
     <description>Mar2</description> 
    </event> 
    <event> 
     <date> 
      <year>2012</year> 
      <month>March</month> 
     </date> 
     <description>Mar3</description> 
    </event> 
    <event> 
     <date> 
      <year>2012</year> 
      <month>July</month> 
     </date> 
     <description>Jul1</description> 
    </event> 
    <event> 
     <date> 
      <year>2012</year> 
      <month>July</month> 
     </date> 
     <description>Jul2</description> 
    </event> 
    <event> 
     <date> 
      <year>2012</year> 
      <month>September</month> 
     </date> 
     <description>Sep1</description> 
    </event> 
    <event> 
     <date> 
      <year>2012</year> 
      <month>October</month> 
     </date> 
     <description>Oct1</description> 
    </event> 
    <event> 
     <date> 
      <year>2012</year> 
      <month>October</month> 
     </date> 
     <description>Oct2</description> 
    </event> 
    <event> 
     <date> 
      <year>2012</year> 
      <month>November</month> 
     </date> 
     <description>Nov1</description> 
    </event> 
    <event> 
     <date> 
      <year>2012</year> 
      <month>November</month> 
     </date> 
     <description>Nov2</description> 
    </event> 
    <event> 
     <date> 
      <year>2012</year> 
      <month>December</month> 
     </date> 
     <description>Dec1</description> 
    </event> 
    <event> 
     <date> 
      <year>2012</year> 
      <month>December</month> 
     </date> 
     <description>Dec2</description> 
    </event> 
    <event> 
     <date> 
      <year>2012</year> 
      <month>December</month> 
     </date> 
     <description>Dec3</description> 
    </event> 
    <event> 
     <date> 
      <year>2013</year> 
      <month>January</month> 
     </date> 
     <description>Jan1</description> 
    </event> 
    <event> 
     <date> 
      <year>2013</year> 
      <month>January</month> 
     </date> 
     <description>Jan2</description> 
    </event> 
</events> 

производит разыскиваемого, правильный результат:

<h2>2012</h2> 
<dl> 
    <dt>January</dt> 
    <dd>Jan1</dd> 
    <dd>Jan2</dd> 
    <dt>March</dt> 
    <dd>Mar1</dd> 
    <dd>Mar2</dd> 
    <dd>Mar3</dd> 
    <dt>July</dt> 
    <dd>Jul1</dd> 
    <dd>Jul2</dd> 
    <dt>September</dt> 
    <dd>Sep1</dd> 
    <dt>October</dt> 
    <dd>Oct1</dd> 
    <dd>Oct2</dd> 
    <dt>November</dt> 
    <dd>Nov1</dd> 
    <dd>Nov2</dd> 
    <dt>December</dt> 
    <dd>Dec1</dd> 
    <dd>Dec2</dd> 
    <dd>Dec3</dd> 
</dl> 
<h2>2013</h2> 
<dl> 
    <dt>January</dt> 
    <dd>Jan1</dd> 
    <dd>Jan2</dd> 
</dl> 

Объяснение:

Правильное использование Muenchian method for grouping - с составными ключами группировки.

+0

Спасибо! Использование ключей снова для меня совершенно новое. Прямо сейчас я нашел другую возможность и опубликую ее как ответ ниже. Просто для моего любопытства: есть ли какое-либо прямое решение для исходного вопроса «Доступ к текущему узлу итерации»? – hielsnoppe

+0

@hielsnoppe: Добро пожаловать. Пожалуйста, определите «прямолинейный» :). Для меня это решение является самым простым решением XSLT 1.0, о котором я знаю - иначе я бы предоставил еще один. –

+0

Позвольте мне сказать так: ваше решение заставляет меня работать, что отлично, но не отвечает на вопрос, есть ли или нет - и в случае да, как - я могу получить доступ к вышеупомянутому свойству. Не важно, потому что это работает. :-) – hielsnoppe

0

@ Ответ Диматина Новатчева более сложный, но я нашел еще одну возможность, которую я хотел бы поделиться. Это не зависит от key s и, следовательно, немного более «новичок». С другой стороны, он также не решает проблему исходного «доступа к текущему узлу итерации»:

<?xml version="1.0" encoding="utf-8"?> 
<xsl:transform version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 

    <xsl:template match="events"> 
     <xsl:for-each select="event[not(date/year=preceding-sibling::event/date/year)]/date/year"> 
      <xsl:call-template name="year"> 
       <xsl:with-param name="year" select="." /> 
      </xsl:call-template> 
     </xsl:for-each> 
    </xsl:template> 

    <xsl:template name="year"> 
     <xsl:param name="year" /> 

     <h2><xsl:value-of select="$year" /></h2> 

     <dl class="dl-horizontal"> 
     <xsl:for-each select="//event[date/year=$year][not(date/month=preceding-sibling::event[date/year=$year]/date/month)]/date/month"> 
      <xsl:call-template name="month"> 
       <xsl:with-param name="month" select="." /> 
       <xsl:with-param name="year" select="$year" /> 
      </xsl:call-template> 
     </xsl:for-each> 
     </dl> 
    </xsl:template> 

    <xsl:template name="month"> 
     <xsl:param name="month" /> 
     <xsl:param name="year" /> 

     <dt><xsl:value-of select="$month" /></dt> 

     <xsl:for-each select="//event[date/year=$year][date/month=$month]"> 
      <xsl:call-template name="event"> 
       <xsl:with-param name="event" select="." /> 
      </xsl:call-template> 
     </xsl:for-each> 
    </xsl:template> 

    <xsl:template name="event"> 
     <xsl:param name="event" /> 

     <dd><xsl:copy-of select="description/node()" /></dd> 
    </xsl:template> 

</xsl:transform> 
+0

Если «иногда он затягивает разметку по неизвестной причине и тоже не решает исходный« доступ к текущему узлу итерации », то« при всем уважении »это на самом деле не решение проблемы –

+0

Абсолютно верно. Найдена ошибка и исправлена. – hielsnoppe