2011-08-18 134 views
1

我知道這裏有一些介紹,但我是XSLT的新手,我試圖在輸入XML中不同位置的節點上嵌套for-each循環,但是在相同的節點級別。XSL Embedded for each

所以......例如:

<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循環內引用不同的節點。

任何幫助,非常感謝。

+0

輸入的XML格式不正確,我想這是一個拼寫錯誤,而不是問題的一部分 - 6行

+0

又一個錯字4日從底線:第二助理 –

回答

1

無需嵌套循環 - 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

這似乎是一個很好的解決方案,但在我實際的XML/XSLT更宏大的方案中,我沒有得到它的工作......我有我的主要XML標記之前的模板match =「/」開頭。 ...所以它不會讓我把其他模板放在該模板中。 – Brian

+0

好,如果我理解你好,你需要避免使用其他模板...我編輯的XSL不使用任何,HTH –

+0

太棒了!我確實弄清楚瞭如何使用模板..他們基本上像一個函數調用。 – Brian

1

你不應該使用嵌套循環(或循環)。

使用輸入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> 

注:到目前爲止,我的答案是唯一一個對輸出進行排序併產生確切結果的方法(減去知名度,形成性錯誤)你想要的。

0

該死,打我吧。哦,不妨給我解決方案:

<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> 
0

你的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

我欣賞所有的解決方案。我真的不明白模板呢...是否與編程中的函數類似?我仍然在學習,所以謝謝大家花時間回答。 – Brian

+0

P.S.這不是我的輸入。我只需要用它來獲得我需要的輸出。我鄙視以這種方式移動數據。我更像是一個與源頭類型聯繫的人......我們只是不住在這個世界。哦,welll,去研究XSL模板。 – Brian

+0

這是一本開始學習Michael Key的XSL-XSLT程序員參考書的好書。有一部分解釋瞭如何不使用編程模式=) –