2012-07-18 141 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