Условное вложение нескольких шаблонов XSLT - PullRequest
3 голосов
/ 16 ноября 2011

Мой XML очень плоский, и вот пример:

<Rows>
  <Row>
    <ProjectID>1000</ProjectID>
    <Phase>Initiation</Phase>
    <ID>1</ID>
    <Name>Work item 1</Name>
    <Master>1</Master>
  </Row>
  <Row>
    <ProjectID>1000</ProjectID>
    <Phase>Initiation</Phase>
    <ID>2</ID>
    <Name>Work item 2</Name>
    <Master>1</Master>
  </Row>
  <Row>
    <ProjectID>1000</ProjectID>
    <Phase>Closing</Phase>
    <ID>3</ID>
    <Name>Work item 3</Name>
    <Master>3</Master>
  </Row>
  <Row>
    <ProjectID>1000</ProjectID>
    <Phase>Closing</Phase>
    <ID>4</ID>
    <Name>Work item 4</Name>
    <Master>3</Master>
  </Row>
  <Row>
    <ProjectID>1000</ProjectID>
    <Phase>Closing</Phase>
    <ID>5</ID>
    <Name>Work item 5</Name>
    <Master>4</Master>
  </Row>
</Rows>

И они должны быть вложены таким образом, чтобы он отображался так:

**Initiation**
Work item 1
  Work item 2
**Closing**
  Work item 3
    Work item 4
      Work item 5

RightТеперь у меня есть шаблон для ProjectID, Phase и Name (например, мой фактический шаблон довольно большой), и я начинаю с шаблона ProjectID, группирую и зацикливаю по фазе, а затем группирую и зацикливаю по фазе по имени.(Итак, я получаю список всех имен по этапам проекта).Он отлично работал только для 2-х уровней (скажем, рабочие элементы 1 и 2), но третий уровень (например, рабочий элемент 5) потерял меня.

Сейчас я пытаюсь перебрать все соответствующие поля Master в имениtemplate (реальный код которого здесь):

<xsl:template name="Deliverable">
    <!--
Parent == True && Lone == True -> Impossible
Parent == True && Lone == False -> Parent
Parent == False && Lone == False -> Child
Parent == False && Lone = True -> Single deliverable -->

    <xsl:param name="parent" />
    <xsl:param name="lone" />

    <xsl:variable name="Parent">
      <xsl:choose>
        <xsl:when test="count(key('project-phase-deliverables', concat(ProjectNo, '|', Phase, '|', IDField2))) > 1">
          1
        </xsl:when>
        <xsl:otherwise>
          0
        </xsl:otherwise>
      </xsl:choose>
    </xsl:variable>

    <xsl:variable name="ID"><xsl:value-of select="generate-id(IDField1)" /></xsl:variable>

    <tr>
      <xsl:choose>
        <!-- JS for parent deliverable -->
        <xsl:when test="$Parent = 'True'">
          <xsl:attribute name="ID">
            <xsl:value-of select="$ID"/>
          </xsl:attribute>
          <script>$('#<xsl:value-of select="$ID"/>').click(function() { $('.<xsl:value-of select="IDField2"/>').toggle(); });</script>
        </xsl:when>
        <!-- Coloring/attributes for children -->
        <xsl:when test="$parent = 'False' and $lone='False'">
          <xsl:attribute name="style">background: #DEDEFF; display: none;</xsl:attribute>
          <xsl:attribute name="class">
            <xsl:value-of select="IDField2"/>
          </xsl:attribute>
        </xsl:when>
      </xsl:choose>

      <td class="doWhite" style="width: 15px; height: 24px; text-align:right; border-right:none;">
        <p class="normal">
          <!-- Parent deliverable expander arrow -->
          <xsl:if test="$Parent = 1">
            <span class="Expander">&#9654;</span>
          </xsl:if>
        </p>
      </td>
      <td class="doWhite" style="width: 200px; height: 24px; border-left:none;">
        <p class="normal">
          <!-- Child deliverable diamond -->
          <xsl:if test="$parent = 'False' and $lone = 'False'">
            <span class="Expander">&#9670; </span>
          </xsl:if>
          <xsl:value-of select="ItemDescription"/>
        </p>
      </td>
      <td class="doWhite" style="width: 130px; height: 24px">
        <p class="normal">
          <xsl:value-of select="Owner"/>
        </p>
      </td>
      <td style="width: 60px; height: 24px">
        <xsl:call-template name="status"/>
      </td>
      <td class="doWhite">
        <p class="normal">
          <xsl:value-of select="ItemNotes"/>
        </p>
      </td>
    </tr>
    <xsl:if test="$Parent = 1">
      <xsl:for-each select="key('project-phase-deliverables', concat(ProjectNo, '|', Phase, '|', IDField2))[position()!=1]">
        <!-- this doesn't recurse properly :( -->
        <xsl:call-template name="Deliverable" />
      </xsl:for-each>
    </xsl:if>
  </xsl:template>

И, как вы можете ожидать, он зацикливается бесконечно и время ожидания истекает.Я чувствую, что могу использовать apply-template для своей проблемы, но как я могу использовать это для эффективной группировки по другим полям (Phase и ProjectID)?

1 Ответ

3 голосов
/ 16 ноября 2011

Возможно, я неправильно понял ваше требование, но, похоже, вы здесь слишком усложняете вещи.

Во-первых, я думаю, что вы Фаза .Поэтому настройте ключ следующим образом:

<xsl:key name="Phase" match="Row" use="Phase" />

И сопоставьте самую верхнюю строку в каждой Фазе , например, так:получить 'дочерние элементы' текущей строки, вы можете рекурсивно вызвать шаблон для соответствия строка элементов

<xsl:apply-templates 
  select="//Row[Phase=current()/Phase][Master=current()/ID][Master != ID]" />

Итак, учитывая следующее XSLT

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
   <xsl:output method="xml" indent="yes"/>
   <xsl:key name="Phase" match="Row" use="Phase"/>

   <xsl:template match="/">
      <Rows>
         <xsl:apply-templates select="//Row[generate-id() = generate-id(key('Phase', Phase)[1])]" mode="first"/>
      </Rows>
   </xsl:template>

   <xsl:template match="Row" mode="first">
      <Phase name="{Phase}">
         <xsl:apply-templates select="key('Phase', Phase)[Master = ID]"/>
      </Phase>
   </xsl:template>

   <xsl:template match="Row" name="Row">
      <xsl:copy>
         <xsl:apply-templates select="@*|node()"/>
         <xsl:apply-templates select="//Row[Phase=current()/Phase][Master=current()/ID][Master != ID]"/>
      </xsl:copy>
   </xsl:template>

   <xsl:template match="@*|node()">
      <xsl:copy>
         <xsl:apply-templates select="@*|node()"/>
      </xsl:copy>
   </xsl:template>
</xsl:stylesheet>

При применении к вашему образцу XML выводится следующее:

<Rows>
   <Phase name="Initiation">
      <Row>
         <ProjectID>1000</ProjectID>
         <Phase>Initiation</Phase>
         <ID>1</ID>
         <Name>Work item 1</Name>
         <Master>1</Master>
         <Row>
            <ProjectID>1000</ProjectID>
            <Phase>Initiation</Phase>
            <ID>2</ID>
            <Name>Work item 2</Name>
            <Master>1</Master>
         </Row>
      </Row>
   </Phase>
   <Phase name="Closing">
      <Row>
         <ProjectID>1000</ProjectID>
         <Phase>Closing</Phase>
         <ID>3</ID>
         <Name>Work item 3</Name>
         <Master>3</Master>
         <Row>
            <ProjectID>1000</ProjectID>
            <Phase>Closing</Phase>
            <ID>4</ID>
            <Name>Work item 4</Name>
            <Master>3</Master>
            <Row>
               <ProjectID>1000</ProjectID>
               <Phase>Closing</Phase>
               <ID>5</ID>
               <Name>Work item 5</Name>
               <Master>4</Master>
            </Row>
         </Row>
      </Row>
   </Phase>
</Rows>

Если вы хотите вывести HTML, попробуйте следующее XSLT

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
   <xsl:output method="html" indent="yes"/>
   <xsl:key name="Phase" match="Row" use="Phase"/>

   <xsl:template match="/">
      <body>
         <xsl:apply-templates select="//Row[generate-id() = generate-id(key('Phase', Phase)[1])]" mode="first"/>
      </body>
   </xsl:template>

   <xsl:template match="Row" mode="first">
      <h1>
         <xsl:value-of select="Phase"/>
      </h1>
      <ul>
         <xsl:apply-templates select="key('Phase', Phase)[Master = ID]"/>
      </ul>
   </xsl:template>

   <xsl:template match="Row" name="Row">
      <li>
         <xsl:value-of select="Name"/>
         <xsl:if test="//Row[Phase=current()/Phase][Master=current()/ID][Master != ID]">
            <ul>
               <xsl:apply-templates select="//Row[Phase=current()/Phase][Master=current()/ID][Master != ID]"/>
            </ul>
         </xsl:if>
      </li>
   </xsl:template>
</xsl:stylesheet>

Это должно вывести следующий HTML

<body>
   <h1>Initiation</h1>
   <ul>
      <li>Work item 1
         <ul>
            <li>Work item 2</li>
         </ul>
      </li>
   </ul>
   <h1>Closing</h1>
   <ul>
      <li>Work item 3
         <ul>
            <li>Work item 4
               <ul>
                  <li>Work item 5</li>
               </ul>
            </li>
         </ul>
      </li>
   </ul>
</body>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...