XSL Embedded для каждого - PullRequest
       13

XSL Embedded для каждого

1 голос
/ 18 августа 2011

Я знаю, что здесь кое-что описано, но я новичок в XSLT и пытаюсь сделать вложенный цикл for-each для узлов, которые находятся в разных местах входного XML, но на одном уровне узлов.

Итак ... например:

    <Level1>
    <Level2>
        <Level3a>
          <Item1>Clothes Washed</Item1>
          <Item2>08/02/2011 06:54</Item2>
          <DoneBy>Ingrid</DoneBy>
        </Level3a>
        <Level3a>
          <Item1>Car Washed</Item1>
          <Item2>08/02/2011 08:25</Item2>
          <DoneBy>Jeanette</DoneBy>
        </Level3a>
        <Level3a>
          <Item1>Dog Walked</Item1>
          <Item2>08/02/2011 10:30</Item2>
          <DoneBy>Ingrid</DoneBy>
        </Level3a>
        <Level3b>
          <DoneWho>Ingrid</DoneWho>
          <JobTitle>Main Asst</JobTitle>
        </Level3b>
        <Level3b>
          <DoneWho>Jeanette</DoneWho>
          <JonTitle>2nd Asst</JobTitle>
        </Level3b>
      </Level2>
    </Level1>

Мне нужно, чтобы вывод был

    <Jobs>
      <CompletedJob>
        <JobTitle>Main Asst</JobTitle>
        <Job>Clothes Washed</Job>
        <CompOn>08/02/2011</CompOn>
        <CompAt>06:54<CompAt>
      </CompletedJob>
      <CompletedJob>
        <JobTitle>Main Asst</JobTitle>
        <Job>Dog Walked</Job>
        <CompOn>08/02/2011</CompOn>
        <CompAt>10:30</CompAt>
      </CompletedJob>
      <CompletedJob>
        <JobTitle>2nd Asst</JobTitle>
        <Job>Car Washed</Job>
        <CompOn>08/02/2011</CompOn>
        <CompAt>08:25</CompAt>
      </CompletedJob>
    </Jobs>

РЕДАКТИРОВАТЬ: пожалуйста, посмотрите изменения в приведенном выше выводе ... Я думаю, это действительно то, что я пытаюсь сделать. Замена на выходе ... спасибо еще раз.

Я пробовал цикл neste for-each, но я не могу сослаться на другой узел внутри основного цикла for-each.

Любая помощь очень ценится.

Ответы [ 4 ]

1 голос
/ 18 августа 2011

Вам не нужно использовать вложенные циклы (или циклы вообще).

Использование фиксированной версии входного XML:

<Level1>
  <Level2>
    <Level3a>
      <Item1>Clothes Washed</Item1>
      <Item2>08/02/2011 06:54</Item2>
      <DoneBy>Ingrid</DoneBy>
    </Level3a>
    <Level3a>
      <Item1>Car Washed</Item1>
      <Item2>08/02/2011 08:25</Item2>
      <DoneBy>Jeanette</DoneBy>
    </Level3a>
    <Level3a>
      <Item1>Dog Walked</Item1>
      <Item2>08/02/2011 10:30</Item2>
      <DoneBy>Ingrid</DoneBy>
    </Level3a>
    <Level3b>
      <DoneWho>Ingrid</DoneWho>
      <JobTitle>Main Asst</JobTitle>
    </Level3b>
    <Level3b>
      <DoneWho>Jeanette</DoneWho>
      <JobTitle>2nd Asst</JobTitle>
    </Level3b>
  </Level2>
</Level1>

и эта таблица стилей:

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

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

  <xsl:template match="/Level1">
    <Jobs>
      <xsl:apply-templates select="*/Level3a">
        <xsl:sort select="DoneBy"/>
      </xsl:apply-templates>
    </Jobs>
  </xsl:template>

  <xsl:template match="Level3a">
    <CompletedJob>
      <Who><xsl:apply-templates select="DoneBy"/></Who>
      <Job><xsl:apply-templates select="Item1"/></Job>
      <!-- XSLT 2.0 option
      <CompOn><xsl:value-of select="tokenize(Item2,' ')[1]"></xsl:value-of></CompOn>
      <CompAt><xsl:value-of select="tokenize(Item2,' ')[2]"></xsl:value-of></CompAt>
      -->
      <CompOn><xsl:value-of select="substring-before(Item2, ' ')"></xsl:value-of></CompOn>
      <CompAt><xsl:value-of select="substring-after(Item2, ' ')"></xsl:value-of></CompAt>
    </CompletedJob>
  </xsl:template>

  <xsl:template match="DoneBy|Item1|Item2">
    <xsl:apply-templates/>
  </xsl:template>

</xsl:stylesheet>

дает желаемый результат:

<Jobs>
   <CompletedJob>
      <Who>Ingrid</Who>
      <Job>Clothes Washed</Job>
      <CompOn>08/02/2011</CompOn>
      <CompAt>06:54</CompAt>
   </CompletedJob>
   <CompletedJob>
      <Who>Ingrid</Who>
      <Job>Dog Walked</Job>
      <CompOn>08/02/2011</CompOn>
      <CompAt>10:30</CompAt>
   </CompletedJob>
   <CompletedJob>
      <Who>Jeanette</Who>
      <Job>Car Washed</Job>
      <CompOn>08/02/2011</CompOn>
      <CompAt>08:25</CompAt>
   </CompletedJob>
</Jobs>

ПРИМЕЧАНИЕ. Пока мой ответ - единственный ответ, который сортирует выходные данные и дает точный результат (за вычетом ошибки правильной формы), который вы хотели.

1 голос
/ 18 августа 2011

Нет необходимости во вложенных циклах - XSLT по своей природе достаточно рекурсивен.

Следующая таблица стилей выполняет свою работу:

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

    <xsl:output method="xml"/>
    <xsl:template match="/">
        <Jobs>
            <xsl:for-each select="*/*/Level3a">
                <xsl:sort select="DoneBy"/>

                <CompletedJob>
                    <JobTitle>
                        <xsl:value-of select="../Level3b[DoneWho=current()/DoneBy]/JobTitle"/>
                    </JobTitle>
                    <Job>
                        <xsl:value-of select="Item1"/>
                    </Job>
                    <CompOn>
                        <xsl:value-of select="substring-before(Item2,' ')"/>
                    </CompOn>
                    <CompAt>
                        <xsl:value-of select="substring-after(Item2,' ')"/>
                    </CompAt>
                </CompletedJob>

            </xsl:for-each>
         </Jobs>
    </xsl:template>

</xsl:stylesheet>

Элементы Level3b теперь используются для разрешения DoneBy в JobTitle.

0 голосов
/ 18 августа 2011

Ваш ввод XML действительно ужасен.

    <xsl:template match="/">
    <xsl:apply-templates select="//Item1"/>
</xsl:template>

<xsl:template match="Item1">
    <CompletedJob>
        <Who><xsl:value-of select="../DoneBy"/></Who>
        <Job><xsl:value-of select="."/></Job>
        <xsl:apply-templates select="../Item2"/>
    </CompletedJob>
</xsl:template>

<xsl:template match="Item2">
    <CompOn><xsl:value-of select="substring-before(text(), ' ')"/></CompOn>
    <CompAt><xsl:value-of select="substring-after(text(), ' ')"/></CompAt>
</xsl:template>

это генерирует ваш вывод

0 голосов
/ 18 августа 2011

Черт, побей меня к этому. О, хорошо, может также дать мое решение:

<Level1>
    <Level2>
        <Level3>
            <Item1>Clothes Washed</Item1>
            <Item2>08/02/2011 06:54</Item2>
            <DoneBy>Ingrid</DoneBy>
        </Level3>
        <Level3>
            <Item1>Car Washed</Item1>
            <Item2>08/02/2011 08:25</Item2>
            <DoneBy>Jeanette</DoneBy>
        </Level3>
        <Level3>
            <Item1>Dog Walked</Item1>
            <Item2>08/02/2011 10:30</Item2>
            <DoneBy>Ingrid</DoneBy>
        </Level3>
    </Level2>
</Level1>


<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="/">
        <Jobs>
        <xsl:for-each select="/Level1/Level2/Level3">
            <CompletedJob>
                <Who><xsl:value-of select="./DoneBy"/></Who>
                <Job><xsl:value-of select="./Item1"/></Job>
                <CompOn><xsl:value-of select="substring(./Item2, 1, 10)"/></CompOn>
                <CompAt><xsl:value-of select="substring(./Item2, 12, 5)"/></CompAt>
            </CompletedJob>
        </xsl:for-each>
        </Jobs>
    </xsl:template>
</xsl:stylesheet>
...