使用非 Muenchian 分组在 xslt 1.0 中对大量数据进行分组的简单方法



我是xslt的新手,因此无法理解这里为我想要实现的目标提供的复杂解决方案。以非Muenchian方式对繁重的数据结构进行分组(意味着有很多属性和元素,因此不能使用任何串联的解决方案)。因为我觉得大数据的串联会影响性能。这是我尝试过的示例输入数据、所需输出和 xsl:

#

输入 xml #

    <out:OuterSegment>
        <out:Segment >
             <out:from Code="CHN"/>
             <out:tothis Code="HYD"/>
             <out:group>0</out:group>
        </out:Segment>
        <out:Segment >
             <out:from Code="HYD"/>
             <out:tothis Code="BLR"/>
             <out:group>1</out:group>
        </out:Segment>
        <out:Segment >
             <out:from Code="BLR"/>
             <out:tothis Code="TVN"/>
             <out:group>2</out:group>
        </out:Segment>
        <out:Segment >
             <out:from Code="TVN"/>
             <out:tothis Code="DEL"/>
             <out:group>2</out:group>
        </out:Segment>
    </out:OuterSegment>

输出 XML

    <out2:OuterSegment>
        <out2:Segment >
             <out2:from Code="CHN"/>
             <out2:tothis Code="HYD"/>
             <out2:group>0</out2:group>
        </out2:Segment>
    </out2:OuterSegment>    
    <out2:OuterSegment>
        <out2:Segment >
             <out2:from Code="HYD"/>
             <out2:tothis Code="BLR"/>
             <out2:group>1</out2:group>
        </out2:Segment>
    </out2:OuterSegment>
    <out2:OuterSegment>
        <out2:Segment >
             <out2:from Code="BLR"/>
             <out2:tothis Code="TVN"/>
             <out2:group>2</out2:group>
        </out2:Segment>
    </out2:OuterSegment>
    <out2:OuterSegment>
        <out2:Segment >
             <out2:from Code="TVN"/>
             <out2:tothis Code="DEL"/>
             <out2:group>2</out2:group>
        </out2:Segment>
    </out2:OuterSegment>

XSL 代码段

    <xsl:choose>
    <xsl:when test="position() = 1">
         <xsl:message> its the first row </xsl:message>
         <out:OuterSegment>            
                <xsl:apply-templates select="in2:IncomingSegment"
                                                    mode="localIncomingSegmentRefToSegment" />
            </out:OuterSegment>
    </xsl:when>
    <xsl:otherwise>
         <xsl:variable name="prevgroup" select="//in2:IncomingSegment[position() - 1]/@Group"/>
         <xsl:message> is the subsequent row</xsl:message>
         <xsl:if test="$prevgroup = //in2:IncomingSegment[$prevgroup]/@Group">
                <xsl:apply-templates select="in2:IncomingSegment"
                                                    mode="localIncomingSegmentRefToSegment" />                      
         </xsl:if>
         <xsl:if test="$prevgroup != //in2:IncomingSegment[$prevgroup]/@Group">
                <out:OuterSegment>     
                        <xsl:apply-templates select="in2:IncomingSegment"
                                                    mode="SegmentRefToSegment" />
                </out:OuterSegment>
         </xsl:if>
    </xsl:otherwise>
    </xsl:choose>

我需要提到,上面的输入xml是由另一个xslt生成的,其输入为:

实际输入 xml

    <in:RefSegment key="1" group="0">
        <in:inSegment >
             <in:from Code="CHN"/>
             <in:tothis Code="HYD"/>
        </in:inSegment>
    </in:RefSegment>
    <in:RefSegment key="2" group="1">
        <in:inSegment >
             <in:from Code="HYD"/>
             <in:tothis Code="BLR"/>
        </in:inSegment>
    </in:RefSegment>
    <in:RefSegment key="3" group="2">
        <in:inSegment >
             <in:from Code="BLR"/>
             <in:tothis Code="TVN"/>
        </in:inSegment>
    </in:RefSegment>
    <in:RefSegment key="4" group="2">
        <in:inSegment >
             <in:from Code="TVN"/>
             <in:tothis Code="BLR"/>
        </in:inSegment>
    </in:RefSegment>
    <in:DataSegments>
        <in:Data >
                    <in:keyref> 0 </in:keyref>
        </in:Data>
        <in:Data >
            <in:keyref> 1 </in:keyref>
        </in:Data>
        <in:Data >
                <in:keyref> 2 </in:keyref>
        </in:Data>
            <in:Data >
                <in:keyref> 2 </in:keyref>
        </in:Data>
  <in:DataSegments>

是否可以一次性从上述实际输入中获得最终输出.xml.xml ?

我不知道

您如何处理有关inout2前缀的输入和输出xml的命名空间,以及命名空间是否是一个问题,所以也许这种方法没有用,但我想分享这个想法。
这是基于以下假设:所有 <in:Data>节点位于与实际输入 XML 所建议的<in:RefSegment>相对应的位置 - 如果不是这种情况,请将其添加到您的问题中,因为有必要按<in:RefSegment>group 属性值和相应的<in:keyref>值进行分组。

作为对输入 XML 代码段的调整,我将<in:RefSegment>节点包装在具有示例命名空间的根节点中:<root xmlns:in="http://www.example.com">并将示例命名空间xmlns:in="http://www.example.com"xmlns:out2="http://www.example2.com"添加到样式表声明中。由于命名空间xmlns:out2,此命名空间将添加到每个out2:OuterSegment节点。

遵循 XSLT

<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:in="http://www.example.com" xmlns:out2="http://www.example2.com"
  exclude-result-prefixes="in" version="1.0">
<xsl:output method="xml" omit-xml-declaration="yes" encoding="UTF-8" indent="yes" />
  <xsl:strip-space elements="*"/>
    <xsl:template match="in:RefSegment">
    <xsl:variable name="position" select="position()"/>
     <out2:OuterSegment>
       <out2:Segment>
         <out2:from>
           <xsl:attribute name="Code">
             <xsl:value-of select="in:inSegment/in:from/@Code" />
           </xsl:attribute>
         </out2:from>
         <out2:tothis Code="HYD">
            <xsl:attribute name="Code">
              <xsl:value-of select="in:inSegment/in:tothis/@Code" />
            </xsl:attribute>
         </out2:tothis>
         <out2:group>
           <xsl:value-of select="normalize-space(//in:DataSegments/in:Data[$position]/in:keyref)"/>
        </out2:group>
      </out2:Segment>
    </out2:OuterSegment>
  </xsl:template>
  <xsl:template match="in:DataSegments"/>
</xsl:transform>

当应用于实际输入 XML 并调整缺失的结束</in:DataSegments>时,会产生以下结果:

<out2:OuterSegment xmlns:out="http://www.example2.com">
  <out2:Segment>
    <out2:from Code="CHN"/>
    <out2:tothis Code="HYD"/>
    <out2:group>0</out2:group>
  </out2:Segment>
</out2:OuterSegment>
<out2:OuterSegment xmlns:out="http://www.example2.com">
  <out2:Segment>
    <out2:from Code="HYD"/>
    <out2:tothis Code="BLR"/>
    <out2:group>1</out2:group>
  </out2:Segment>
</out2:OuterSegment>
<out2:OuterSegment xmlns:out="http://www.example2.com">
  <out2:Segment>
    <out2:from Code="BLR"/>
    <out2:tothis Code="TVN"/>
    <out2:group>2</out2:group>
  </out2:Segment>
</out:OuterSegment>
<out:OuterSegment xmlns:out="http://www.example2.com">
   <out2:Segment>
     <out2:from Code="TVN"/>
     <out2:tothis Code="BLR"/>
     <out2:group>2</out2:group>
   </out2:Segment>
</out2:OuterSegment>

in:RefSegment节点匹配的模板<xsl:template match="in:RefSegment">生成<out2:OuterSegment>节点。<xsl:variable name="position" select="position()"/>是当前在:RefSegment中的位置。
生成的out2:fromout2:tothis节点的属性是从当前处理的in:RefSegment中检索的:

<out2:from>
   <xsl:attribute name="Code">
        <xsl:value-of select="in:inSegment/in:from/@Code" />
    </xsl:attribute>
</out2:from>

以及从位于同一位置的in:Data节点检索out2:group的值:

<out2:group>
  <xsl:value-of select="normalize-space(//in:DataSegments
                        /in:Data[$position/in:keyref)"/>
</out2:group>

使用额外的normalize-space()来删除输入中的空间。
模板匹配in:DataSegments <xsl:template match="in:DataSegments"/>为空,因此in:DataSegments节点将从输出中删除。

最新更新