按特定值分组并使用xslt 1.0生成序列号

时间:2017-12-11 15:49:44

标签: xml xpath xslt-1.0

我试图根据旅行社提供的多种旅行来制定假期计划。因此,我有多次旅行,我必须链接(基于旅行社)并为我访问的每个位置生成序列号(包括每天的开始和结束位置)。谢谢! 例如:2个来自一个机构的旅行

旅行日1:

  • 1 - 开始位置(代理处)
  • 2 - 目标1
  • 3 - 目标2
  • 4 - 结束位置(酒店)

旅行日2:

  • 1 - 开始位置(酒店)
  • 2 - 目标3
  • 3 - 结束位置(酒店)

旅行日3:

  • 1 - 开始位置(酒店)
  • 2 - 结束位置(代理处)

从这3次旅行中我想得到一次这样的旅行:

旅行1:

  • 1 - 开始位置(代理处)
  • 2 - 目标1
  • 3 - 目标2
  • 4 - 结束位置(酒店)/从旅行第2天开始的位置(这与我只需要添加一次的原因相同)
  • 5 - 目标3
  • 6 - 结束位置(酒店)/从旅行第3天开始的位置(这与我只需要添加一次的原因相同)
  • 7 - 结束位置(代理处)

输入xml:

<HolidayPlan>
    <!-- first holiday -->
    <Travel>
        <UniqueTravelID>100-1</UniqueTravelID>
        <TravelAgency>Agency1</TravelAgency>
        <StartLocationID>A</StartLocationID>
        <EndLocationID>B</EndLocationID>
        <Day>1</Day>
        <IntermediateObjectives>
            <Objective1>
                <UniqueObjectiveID>Objective1</UniqueObjectiveID>
                <ObjectiveNumber>1</ObjectiveNumber>
            </Objective1>
            <Objective2>
                <UniqueObjectiveID>Objective2</UniqueObjectiveID>
                <ObjectiveNumber>2</ObjectiveNumber>
            </Objective2>
        </IntermediateObjectives>
    </Travel>
    <Travel>
        <UniqueTravelID>100-1</UniqueTravelID>
        <TravelAgency>Agency1</TravelAgency>
        <StartLocationID>B</StartLocationID>
        <EndLocationID>B</EndLocationID>
        <Day>2</Day>
        <IntermediateObjectives>
            <Objective1>
                <UniqueObjectiveID>Objective3</UniqueObjectiveID>
                <ObjectiveNumber>1</ObjectiveNumber>
            </Objective1>
        </IntermediateObjectives>
    </Travel>
    <Travel>
        <UniqueTravelID>100-3</UniqueTravelID>
        <TravelAgency>Agency1</TravelAgency>
        <StartLocationID>B</StartLocationID>
        <EndLocationID>A</EndLocationID>
        <Day>3</Day>
        <IntermediateObjectives>
        </IntermediateObjectives>
    </Travel>

    <!-- second holiday -->
    <Travel>
        <UniqueTravelID>200-1</UniqueTravelID>
        <TravelAgency>Agency2</TravelAgency>
        <StartLocationID>C</StartLocationID>
        <EndLocationID>D</EndLocationID>
        <Day>1</Day>
        <IntermediateObjectives>
            <Objective1>
                <UniqueObjectiveID>Objective1</UniqueObjectiveID>
                <ObjectiveNumber>1</ObjectiveNumber>
            </Objective1>
        </IntermediateObjectives>
    </Travel>
    <Travel>
        <UniqueTravelID>200-2</UniqueTravelID>
        <TravelAgency>Agency2</TravelAgency>
        <StartLocationID>D</StartLocationID>
        <EndLocationID>C</EndLocationID>
        <Day>2</Day>
        <IntermediateObjectives>
        </IntermediateObjectives>
    </Travel>
</HolidayPlan>

预期结果:

<VisitedPlaces>
    <Place>
        <UniqueTravelID>100-1</UniqueTravelID>
        <TravelAgency>Agency1</TravelAgency>
        <UniqueObjectiveID>A</UniqueObjectiveID>
        <ObjectiveNumber>1</ObjectiveNumber>
    </Place>
    <Place>
        <UniqueTravelID>100-1</UniqueTravelID>
        <TravelAgency>Agency1</TravelAgency>
        <UniqueObjectiveID>Objective1</UniqueObjectiveID>
        <ObjectiveNumber>2</ObjectiveNumber>
    </Place>
    <Place>
        <UniqueTravelID>100-1</UniqueTravelID>
        <TravelAgency>Agency1</TravelAgency>
        <UniqueObjectiveID>Objective2</UniqueObjectiveID>
        <ObjectiveNumber>3</ObjectiveNumber>
    </Place>
        <Place>
        <UniqueTravelID>100-1</UniqueTravelID>
        <TravelAgency>Agency1</TravelAgency>
        <UniqueObjectiveID>B</UniqueObjectiveID>
        <ObjectiveNumber>4</ObjectiveNumber>
    </Place>
    <Place>
        <UniqueTravelID>100-1</UniqueTravelID>
        <TravelAgency>Agency1</TravelAgency>
        <UniqueObjectiveID>Objective3</UniqueObjectiveID>
        <ObjectiveNumber>5</ObjectiveNumber>
    </Place>
    <Place>
        <UniqueTravelID>100-1</UniqueTravelID>
        <TravelAgency>Agency1</TravelAgency>
        <UniqueObjectiveID>B</UniqueObjectiveID>
        <ObjectiveNumber>6</ObjectiveNumber>
    </Place>
    <Place>
        <UniqueTravelID>100-1</UniqueTravelID>
        <TravelAgency>Agency1</TravelAgency>
        <UniqueObjectiveID>A</UniqueObjectiveID>
        <ObjectiveNumber>7</ObjectiveNumber>
    </Place>

    <Place>
        <UniqueTravelID>200-1</UniqueTravelID>
        <TravelAgency>Agency2</TravelAgency>
        <UniqueObjectiveID>C</UniqueObjectiveID>
        <ObjectiveNumber>1</ObjectiveNumber>
    </Place>
    <Place>
        <UniqueTravelID>200-1</UniqueTravelID>
        <TravelAgency>Agency2</TravelAgency>
        <UniqueObjectiveID>Objerctive1</UniqueObjectiveID>
        <ObjectiveNumber>2</ObjectiveNumber>
    </Place>
    <Place>
        <UniqueTravelID>200-1</UniqueTravelID>
        <TravelAgency>Agency2</TravelAgency>
        <UniqueObjectiveID>D</UniqueObjectiveID>
        <ObjectiveNumber>3</ObjectiveNumber>
    </Place>
        <Place>
        <UniqueTravelID>200-1</UniqueTravelID>
        <TravelAgency>Agency2</TravelAgency>
        <UniqueObjectiveID>C</UniqueObjectiveID>
        <ObjectiveNumber>4</ObjectiveNumber>
    </Place>
</VisitedPlaces>

1 个答案:

答案 0 :(得分:0)

我正在为 Place 结构创建模板作为第一阶段以使代码更清晰,然后创建用于按 TravelAgency 创建结构的模板,并在主模板中传递它们并重复预防,请参阅下面的XSL(在评论中有一些解释):

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> 
    <xsl:output method="xml" />
    <!--create Place structure-->
    <xsl:template name="place">
        <xsl:param name="param.travel.id"/>
        <xsl:param name="param.travel.agency"/> 
        <xsl:param name="param.object.id"/>
        <xsl:param name="param.object.number"/>  
        <Place>                
            <UniqueTravelID>                    
                <xsl:value-of select="$param.travel.id"/>                
            </UniqueTravelID>                
            <TravelAgency>                    
                <xsl:value-of select="$param.travel.agency"/>                
            </TravelAgency>                
            <UniqueObjectiveID>                    
                <xsl:value-of select="$param.object.id"/>                                    
            </UniqueObjectiveID>                
            <ObjectiveNumber>                    
                <xsl:value-of select="$param.object.number"/>                
            </ObjectiveNumber>            
        </Place>        
    </xsl:template>    
    <!--create template with Place filter by Agency--> 
    <xsl:template name="filter-place">
        <xsl:param name="param.agency"/>   
        <xsl:for-each select="/HolidayPlan/Travel[TravelAgency = $param.agency]">
            <xsl:variable name="var.travel.id" select="/HolidayPlan/Travel[TravelAgency = $param.agency][1]/UniqueTravelID"/>
            <xsl:variable name="var.travel.agency" select="/HolidayPlan/Travel[TravelAgency = $param.agency][1]/TravelAgency"/>
            <xsl:variable name="var.prev.obj.count" select="count(preceding::Travel[TravelAgency = $param.agency]/IntermediateObjectives//UniqueObjectiveID[1])"/>                      
            <xsl:variable name="var.object.number" select="position() + $var.prev.obj.count"/>
            <!--create day counter from Day-->
            <xsl:variable name="var.day">                    
                <xsl:choose>                        
                    <xsl:when test="normalize-space(Day) = '1'">                            
                        <xsl:value-of select="Day"/>                        
                    </xsl:when>
                    <xsl:otherwise>
                        <xsl:value-of select="Day + $var.prev.obj.count"/>
                    </xsl:otherwise>
                </xsl:choose>                
            </xsl:variable>    
            <!--apply Place structure from Travel-->
            <xsl:call-template name="place">
                <xsl:with-param name="param.travel.id" select="$var.travel.id"/>
                <xsl:with-param name="param.travel.agency" select="$var.travel.agency"/>
                <xsl:with-param name="param.object.id" select="StartLocationID"/>
                <xsl:with-param name="param.object.number" select="$var.day"/>    
            </xsl:call-template>
            <!--apply Place structure from IntermediateObjectives-->            
            <xsl:if test="IntermediateObjectives/*">
                <xsl:for-each select="IntermediateObjectives/*">
                        <xsl:call-template name="place">
                            <xsl:with-param name="param.travel.id" select="$var.travel.id"/>
                            <xsl:with-param name="param.travel.agency" select="$var.travel.agency"/>
                            <xsl:with-param name="param.object.id" select="./UniqueObjectiveID"/>
                            <!--Day counter from IntermediateObjectives-->
                            <xsl:with-param name="param.object.number" select="$var.day + ./ObjectiveNumber"/>
                        </xsl:call-template>               
                </xsl:for-each>
            </xsl:if>
        </xsl:for-each>
        <!--create counter variables for last day-->
        <xsl:variable name="travel.count" select="count(/HolidayPlan/Travel[TravelAgency = $param.agency])" />
        <xsl:variable name="all.obj.count" select="count(/HolidayPlan/Travel[TravelAgency = $param.agency]/IntermediateObjectives/*/UniqueObjectiveID)" /> 
        <!--apply Place structure for last day-->                                       
        <xsl:call-template name="place">
            <xsl:with-param name="param.travel.id" select="/HolidayPlan/Travel[TravelAgency = $param.agency][1]/UniqueTravelID"/>
            <xsl:with-param name="param.travel.agency" select="/HolidayPlan/Travel[TravelAgency = $param.agency][1]/TravelAgency"/>
            <xsl:with-param name="param.object.id" select="/HolidayPlan/Travel[TravelAgency = $param.agency][position() = $travel.count]/EndLocationID"/>
            <!--calculation last counter as next Travel Days + Intermediate Objectives + First Day-->
            <xsl:with-param name="param.object.number" select="$travel.count + $all.obj.count + 1"/>
        </xsl:call-template>                                         
    </xsl:template>
    <!--main template - VisitedPlaces structure-->
    <xsl:template match="/"> 
        <VisitedPlaces>                                                               
            <xsl:for-each select="/HolidayPlan/Travel">
                <!--preventing TravelAgency values duplicates and pass to filter-place template as parameter-->            
                <xsl:if test="not(preceding::Travel[TravelAgency/text() = current()/TravelAgency/text()])">                                                    
                    <xsl:call-template name="filter-place">                                            
                        <xsl:with-param name="param.agency" select="./TravelAgency"/>                                    
                    </xsl:call-template>                          
                </xsl:if>                 
            </xsl:for-each>
        </VisitedPlaces>         
    </xsl:template>
</xsl:stylesheet>

结果如预期:

<?xml version="1.0" encoding="UTF-8"?>
<VisitedPlaces>
    <Place>
        <UniqueTravelID>100-1</UniqueTravelID>
        <TravelAgency>Agency1</TravelAgency>
        <UniqueObjectiveID>A</UniqueObjectiveID>
        <ObjectiveNumber>1</ObjectiveNumber>
    </Place>
    <Place>
        <UniqueTravelID>100-1</UniqueTravelID>
        <TravelAgency>Agency1</TravelAgency>
        <UniqueObjectiveID>Objective1</UniqueObjectiveID>
        <ObjectiveNumber>2</ObjectiveNumber>
    </Place>
    <Place>
        <UniqueTravelID>100-1</UniqueTravelID>
        <TravelAgency>Agency1</TravelAgency>
        <UniqueObjectiveID>Objective2</UniqueObjectiveID>
        <ObjectiveNumber>3</ObjectiveNumber>
    </Place>
    <Place>
        <UniqueTravelID>100-1</UniqueTravelID>
        <TravelAgency>Agency1</TravelAgency>
        <UniqueObjectiveID>B</UniqueObjectiveID>
        <ObjectiveNumber>4</ObjectiveNumber>
    </Place>
    <Place>
        <UniqueTravelID>100-1</UniqueTravelID>
        <TravelAgency>Agency1</TravelAgency>
        <UniqueObjectiveID>Objective3</UniqueObjectiveID>
        <ObjectiveNumber>5</ObjectiveNumber>
    </Place>
    <Place>
        <UniqueTravelID>100-1</UniqueTravelID>
        <TravelAgency>Agency1</TravelAgency>
        <UniqueObjectiveID>B</UniqueObjectiveID>
        <ObjectiveNumber>6</ObjectiveNumber>
    </Place>
    <Place>
        <UniqueTravelID>100-1</UniqueTravelID>
        <TravelAgency>Agency1</TravelAgency>
        <UniqueObjectiveID>A</UniqueObjectiveID>
        <ObjectiveNumber>7</ObjectiveNumber>
    </Place>
    <Place>
        <UniqueTravelID>200-1</UniqueTravelID>
        <TravelAgency>Agency2</TravelAgency>
        <UniqueObjectiveID>C</UniqueObjectiveID>
        <ObjectiveNumber>1</ObjectiveNumber>
    </Place>
    <Place>
        <UniqueTravelID>200-1</UniqueTravelID>
        <TravelAgency>Agency2</TravelAgency>
        <UniqueObjectiveID>Objective1</UniqueObjectiveID>
        <ObjectiveNumber>2</ObjectiveNumber>
    </Place>
    <Place>
        <UniqueTravelID>200-1</UniqueTravelID>
        <TravelAgency>Agency2</TravelAgency>
        <UniqueObjectiveID>D</UniqueObjectiveID>
        <ObjectiveNumber>3</ObjectiveNumber>
    </Place>
    <Place>
        <UniqueTravelID>200-1</UniqueTravelID>
        <TravelAgency>Agency2</TravelAgency>
        <UniqueObjectiveID>C</UniqueObjectiveID>
        <ObjectiveNumber>4</ObjectiveNumber>
    </Place>
</VisitedPlaces> 

希望它对您的案件有所帮助。