2012-07-18 217 views
2

我想爲別人解決這個問題,並且自己遇到了問題。XSLT選擇當前的特定節點

我有XML:

<Process> 
    <name>Pro1</name> 
    <duration>Dur1</duration> 
    <time>Time1</time> 
    <name>Pro2</name> 
    <duration>Dur2</duration> 
    <time>Time2</time> 
    <name>Pro3</name> 
    <duration>Dur3</duration> 
    <time>Time3</time> 
    <name>Pro4</name> 
    <duration>Dur4</duration> 
    <time>Time4</time> 
    <name>Pro5</name> 
    <duration>Dur5</duration> 
    <time>Time5</time> 
</Process> 

輸出:

<Process> 
    <Process_Info> 
    <name>Pro1</name> 
    <duration>Dur1</duration> 
    <time>Time1</time> 
    </Process_Info> 
    <Process_Info> 
    <name>Pro2</name> 
    <duration>Dur2</duration> 
    <time>Time2</time> 
    </Process_Info> 
    <Process_Info> 
    <name>Pro3</name> 
    <duration>Dur3</duration> 
    <time>Time3</time> 
    </Process_Info> 
    <Process_Info> 
    <name>Pro4</name> 
    <duration>Dur4</duration> 
    <time>Time4</time> 
    </Process_Info> 
    <Process_Info> 
    <name>Pro5</name> 
    <duration>Dur5</duration> 
    <time>Time5</time> 
    </Process_Info> 
</Process> 

使用XSLT:

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

    <xsl:variable name ="varProcess" select ="Process"/> 

    <xsl:template match="Process"> 
    <xsl:element name="Process"> 
     <xsl:for-each select ="name"> 
     <xsl:variable name ="posName" select ="position()"/> 
     <xsl:element name ="Process_Info"> 
      <xsl:copy-of select ="."/> 
      <xsl:copy-of select="$varProcess/duration[$posName]"/> 
      <xsl:copy-of select="$varProcess/time[$posName]"/> 
     </xsl:element> 
     </xsl:for-each> 
    </xsl:element> 
    </xsl:template> 
</xsl:stylesheet> 

然而,<duration><time>節點並不總是存在和<name>是唯一的保證節點。因此,如果有人錯過了我的position()選擇失敗。

即使<duration>和/或<time>不存在,我如何更改XSLT以允許其工作。

我的理論是,你選擇當前名稱節點下面的兩個節點,如果他們是<duration><time>他們被複制?但不知道如何實現。

當前輸出導致問題的示例。

輸入:

<Process> 
    <name>Pro1</name> 
    <duration>Dur1</duration> 
    <time>Time1</time> 
    <name>Pro2</name> 
    <duration>Dur2</duration> 
    <time>Time2</time> 
    <name>Pro3</name> 
    <duration>Dur3</duration> 
    <time>Time3</time> 
    <name>Pro4</name> 
    <time>Time4</time> 
    <name>Pro5</name> 
    <duration>Dur5</duration> 
</Process> 

輸出:

<Process> 
    <Process_Info> 
    <name>Pro1</name> 
    <duration>Dur1</duration> 
    <time>Time1</time> 
    </Process_Info> 
    <Process_Info> 
    <name>Pro2</name> 
    <duration>Dur2</duration> 
    <time>Time2</time> 
    </Process_Info> 
    <Process_Info> 
    <name>Pro3</name> 
    <duration>Dur3</duration> 
    <time>Time3</time> 
    </Process_Info> 
    <Process_Info> 
    <name>Pro4</name> 
    <duration>Dur5</duration> <!-- Should be in the below process_info --> 
    <time>Time4</time> 
    </Process_Info> 
    <Process_Info> 
    <name>Pro5</name> 
    </Process_Info> 
</Process> 

回答

2

這是卓有成效的,儘管在方法有點 '手動'。可能有更優雅的方式來實現這一

<xsl:template match="Process"> 
    <xsl:element name="Process"> 
     <xsl:for-each select ="name"> 
      <xsl:element name ="Process_Info"> 
       <xsl:copy-of select ="."/> 
       <xsl:variable name="firstSib" select="local-name(following-sibling::*[1])" /> 
       <xsl:variable name="secondSib" select="local-name(following-sibling::*[2])" /> 
       <xsl:choose> 
        <xsl:when test="$firstSib='duration'"> 
         <xsl:copy-of select="following-sibling::*[1]"/> 
         <xsl:choose> 
          <xsl:when test="$secondSib='time'"> 
           <xsl:copy-of select="following-sibling::*[2]"/> 
          </xsl:when> 
          <xsl:otherwise> 
           <time>SomeDefaultValueForMissingTime</time> 
          </xsl:otherwise> 
         </xsl:choose> 
        </xsl:when> 
        <xsl:when test="$firstSib='time'"> 
         <duration>SomeDefaultValueForMissingDuration</duration> 
         <xsl:copy-of select="following-sibling::*[1]"/> 
        </xsl:when> 
        <xsl:otherwise> 
         <duration>SomeDefaultValueForMissingDuration</duration> 
         <time>SomeDefaultValueForMissingTime</time> 
        </xsl:otherwise> 
       </xsl:choose> 
      </xsl:element> 
     </xsl:for-each> 
    </xsl:element> 
</xsl:template> 

輸入:

<Process> 
    <name>Pro1</name> 
    <duration>Dur1</duration> 
    <time>Time1</time> 
    <name>NameMissingDuration</name> 
    <time>TimeMissingDuration</time> 
    <name>NameMissingTime</name> 
    <duration>DurMissingTime</duration> 
    <name>NameMissingBoth</name> 
    <name>NormalName</name> 
    <duration>NormalDuration</duration> 
    <time>NormalTime</time> 
</Process> 

輸出

<Process> 
    <Process_Info> 
    <name>Pro1</name> 
    <duration>Dur1</duration> 
    <time>Time1</time> 
    </Process_Info> 
    <Process_Info> 
    <name>NameMissingDuration</name> 
    <duration>SomeDefaultValueForMissingDuration</duration> 
    <time>TimeMissingDuration</time> 
    </Process_Info> 
    <Process_Info> 
    <name>NameMissingTime</name> 
    <duration>DurMissingTime</duration> 
    <time>SomeDefaultValueForMissingTime</time> 
    </Process_Info> 
    <Process_Info> 
    <name>NameMissingBoth</name> 
    <duration>SomeDefaultValueForMissingDuration</duration> 
    <time>SomeDefaultValueForMissingTime</time> 
    </Process_Info> 
    <Process_Info> 
    <name>NormalName</name> 
    <duration>NormalDuration</duration> 
    <time>NormalTime</time> 
    </Process_Info> 
</Process> 
+1

我給它一小段時間,看看是否有其他用你自己的話說'創造更優雅'的方法,否則將使用它並相應標記。已經明確從您的迴應中瞭解到,並沒有意識到初學者的後續兄弟姐妹:) – Mike 2012-07-18 08:49:18

+0

標記爲答案,因爲您的回覆爲我提供了XSLT所需的工具。我將發佈我的適應性,刪除不需要的默認字段,將字體大小縮小一點。 – Mike 2012-07-18 09:46:25

1

基於關閉nonnb的響應,因此所有歸功於他,最終正在使用XSLT。我的錯誤是不包括在我不需要填充節點的問題中。

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

    <xsl:template match="Process"> 
    <xsl:element name="Process"> 
     <xsl:for-each select ="name"> 
     <xsl:element name ="Process_Info"> 
      <xsl:copy-of select ="."/> 
      <xsl:variable name="firstSib" select="local-name(following-sibling::*[1])" /> 
      <xsl:variable name="secondSib" select="local-name(following-sibling::*[2])" /> 
      <xsl:if test ="($firstSib='duration') or ($firstSib='time')"> 
      <xsl:copy-of select="following-sibling::*[1]"/> 
      </xsl:if> 
      <xsl:if test ="($secondSib='duration') or ($secondSib='time')"> 
      <xsl:copy-of select="following-sibling::*[2]"/> 
      </xsl:if> 
     </xsl:element> 
     </xsl:for-each> 
    </xsl:element> 
    </xsl:template> 
</xsl:stylesheet> 
2

這是一個替代解決方案,沒有xsl:if

這表明使用用於測試節點平等generate-id()功能中選擇下面的電流名稱元件,其第一前名稱元件是當前元素的第一時間(或持續時間)元件。

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

    <xsl:template match="Process"> 
    <xsl:copy> 
     <xsl:apply-templates select="name"/> 
    </xsl:copy> 
    </xsl:template> 

    <xsl:template match="name"> 
    <xsl:variable name="this" select="generate-id()"/> 
    <Process_Info> 
     <xsl:copy-of select="."/> 
     <xsl:copy-of select="following-sibling::duration 
          [generate-id(preceding-sibling::name[1]) = $this] 
          [1]"/> 
     <xsl:copy-of select="following-sibling::time 
          [generate-id(preceding-sibling::name[1]) = $this] 
          [1]"/> 
    </Process_Info> 
    </xsl:template> 

</xsl:stylesheet> 
+0

另一個有趣的答案與我的學習曲線也感謝輸入 – Mike 2012-07-18 12:00:26