【问题标题】:Handling multiple Conditional Looping in XSLT在 XSLT 中处理多个条件循环
【发布时间】:2016-01-04 11:15:27
【问题描述】:

我有一个示例消息,必须使用 XSLT 将其转换为不同的输出结构。

传入的消息是

 <document>
    <ObjectId>
    <ID>1000909090</ID>
    <dlex>
        <attrGroupMany name="streetinfo">
            <row>                                              <!-- Mandatory Loop -->
                <attr name="streetcode">AS_DRAINED</attr> 
                <attrQualMany name="streetintake">             <!-- Optional Loop -->
                    <value qual="en">dvif1</value>
                    <value qual="nl">dvif2</value>
                </attrQualMany>
                <attr name="streettype">BY_MEASURE</attr>
                <attrQual name="streetbasis" qual="ONZ">5</attrQual>
                <attrQual name="streetsize" qual="EA">1</attrQual>
                <attrQualMany name="streetsizeDescription">    <!-- Optional Loop -->
                    <value qual="en">sz1</value>
                    <value qual="hi">sz2</value>
                </attrQualMany>
                <attrGroupMany name="streetDetails">
                    <row>                                     <!-- Optional Loop -->
                        <attr name="streetTypeCode">FAT</attr>
                        <attr name="streetValueIntakePercent">25</attr>
                        <attr name="streetPrecisionCode">APPROXIMATELY</attr>
                        <attrQualMany name="streetContained">   <!-- Optional Loop -->
                            <value qual="ONZ">2</value>
                            <value qual="OZA">3</value>
                        </attrQualMany>
                    </row>
                    <row>
                        <attr name="streetTypeCode">FAMS</attr>
                        <attr name="streetValueIntakePercent">999</attr>
                        <attr name="streetPrecisionCode">EXACT</attr>
                        <attrQualMany name="streetContained">
                            <value qual="ONZ">4</value>
                            <value qual="OZA">5</value>
                        </attrQualMany>
                    </row>
                </attrGroupMany>
            </row>
        </attrGroupMany>
    </dlex>
</ObjectId>
</document>

输出消息是

<?xml version="1.0" encoding="UTF-8"?>
<CatalogObjectId>
<RelationshipData>
  <Relationship>
     <RelationType>ObjectId_Street</RelationType>
     <RelatedObjectIds>
        <RelatedObjectId referenceKey="ObjectId_Street-1-AS_DRAINED-dvif1-en-sz1-en-FAT-2-ONZ" />
        <RelatedObjectId referenceKey="ObjectId_Street-1-AS_DRAINED-dvif1-en-sz1-en-FAT-3-OZA" />
        <RelatedObjectId referenceKey="ObjectId_Street-1-AS_DRAINED-dvif1-en-sz1-en-FAMS-4-ONZ" />
        <RelatedObjectId referenceKey="ObjectId_Street-1-AS_DRAINED-dvif1-en-sz1-en-FAMS-5-OZA" />
        <RelatedObjectId referenceKey="ObjectId_Street-1-AS_DRAINED-dvif1-en-sz2-hi-FAT-2-ONZ" />
        <RelatedObjectId referenceKey="ObjectId_Street-1-AS_DRAINED-dvif1-en-sz2-hi-FAT-3-OZA" />
        <RelatedObjectId referenceKey="ObjectId_Street-1-AS_DRAINED-dvif1-en-sz2-hi-FAMS-4-ONZ" />
        <RelatedObjectId referenceKey="ObjectId_Street-1-AS_DRAINED-dvif1-en-sz2-hi-FAMS-5-OZA" />
        <RelatedObjectId referenceKey="ObjectId_Street-1-AS_DRAINED-dvif2-nl-sz1-en-FAT-2-ONZ" />
        <RelatedObjectId referenceKey="ObjectId_Street-1-AS_DRAINED-dvif2-nl-sz1-en-FAT-3-OZA" />
        <RelatedObjectId referenceKey="ObjectId_Street-1-AS_DRAINED-dvif2-nl-sz1-en-FAMS-4-ONZ" />
        <RelatedObjectId referenceKey="ObjectId_Street-1-AS_DRAINED-dvif2-nl-sz1-en-FAMS-5-OZA" />
        <RelatedObjectId referenceKey="ObjectId_Street-1-AS_DRAINED-dvif2-nl-sz2-hi-FAT-2-ONZ" />
        <RelatedObjectId referenceKey="ObjectId_Street-1-AS_DRAINED-dvif2-nl-sz2-hi-FAT-3-OZA" />
        <RelatedObjectId referenceKey="ObjectId_Street-1-AS_DRAINED-dvif2-nl-sz2-hi-FAMS-4-ONZ" />
        <RelatedObjectId referenceKey="ObjectId_Street-1-AS_DRAINED-dvif2-nl-sz2-hi-FAMS-5-OZA" />
     </RelatedObjectIds>
  </Relationship>
</RelationshipData>
</CatalogObjectId>

当我们使用下面的 XSLT 时,这是完美的。

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" indent="yes" />
<xsl:template match="document">
    <CatalogObjectId>
        <RelationshipData>
            <Relationship>
                <RelationType>ObjectId_Street</RelationType>
                <RelatedObjectIds>
                    <xsl:for-each select="ObjectId/dlex/attrGroupMany[@name='streetinfo']/row">  
                        <xsl:variable name="v_position_streetinfo" select="position()" />                                                   
                        <xsl:variable name="v_streetcode">
                            <xsl:value-of select="attr[@name='streetcode'])"/>
                        </xsl:variable>                 
                        <xsl:variable name="v_streetintake" select="attrQualMany[@name = 'streetintake']/value" />
                        <xsl:variable name="v_streetsizeDescription" select="attrQualMany[@name = 'streetsizeDescription']/value" />
                        <xsl:variable name="v_streetDetails" select="attrGroupMany[@name = 'streetDetails']/row" />                         
                        <xsl:for-each select="$v_streetintake">
                            <xsl:variable name="v_streetintakevalue" select="." />
                            <xsl:variable name="v_streetintakequal" select="./@qual" />
                            <xsl:for-each select="$v_streetsizeDescription">
                                <xsl:variable name="v_streetsizeDescriptionvalue" select="." />
                                <xsl:variable name="v_streetsizeDescriptionqual" select="./@qual" />
                                <xsl:for-each select="$v_streetDetails">
                                    <xsl:variable name="v_streetTypeCode">
                                        <xsl:value-of select="attr[@name='streetTypeCode'])"/>
                                    </xsl:variable> 
                                    <xsl:variable name="v_streetContained" select="attrQualMany[@name = 'streetContained']/value" />
                                    <xsl:for-each select="$v_streetContained">
                                        <xsl:variable name="v_streetContainedvalue" select="." />
                                        <xsl:variable name="v_streetContainedqual" select="./@qual" />
                                        <RelatedObjectId>
                                            <xsl:attribute name="referenceKey">                                                                      
                                                <xsl:value-of select="concat('ObjectId_Street','-',$v_position_streetinfo,'-',$v_streetcode,'-',$v_streetintakevalue,'-',$v_streetintakequal,'-',$v_streetsizeDescriptionvalue,'-',$v_streetsizeDescriptionqual,'-',$v_streetTypeCode,'-',$v_streetContainedvalue,'-',$v_streetContainedqual)"/>                         
                                            </xsl:attribute>                
                                        </RelatedObjectId> 
                                    </xsl:for-each>
                                </xsl:for-each>
                            </xsl:for-each>
                        </xsl:for-each>
                    </xsl:for-each>
                </RelatedObjectIds>
            </Relationship> 
        </RelationshipData>
    </CatalogObjectId>
</xsl:template>
</xsl:stylesheet>

但是当任何可选循环没有出现时,它就不起作用了。当所有可选循环都存在时,我已经编写了 XSLT,当任何 1 或 2 或 3 个或没有可选组出现消息时,我如何编写 XSLT。请建议

预期输出

当第一个可选组不存在时,输出将有 8 条记录。

<?xml version="1.0" encoding="UTF-8"?>
<CatalogObjectId>
  <RelationshipData>
   <Relationship>
     <RelationType>ObjectId_Street</RelationType>
     <RelatedObjectIds>
        <RelatedObjectId referenceKey="ObjectId_Street-1-AS_DRAINED--en-sz1-en-FAT-2-ONZ" />
        <RelatedObjectId referenceKey="ObjectId_Street-1-AS_DRAINED--en-sz1-en-FAT-3-OZA" />
        <RelatedObjectId referenceKey="ObjectId_Street-1-AS_DRAINED--en-sz1-en-FAMS-4-ONZ" />
        <RelatedObjectId referenceKey="ObjectId_Street-1-AS_DRAINED--en-sz1-en-FAMS-5-OZA" />
        <RelatedObjectId referenceKey="ObjectId_Street-1-AS_DRAINED--en-sz2-hi-FAT-2-ONZ" />
        <RelatedObjectId referenceKey="ObjectId_Street-1-AS_DRAINED--en-sz2-hi-FAT-3-OZA" />
        <RelatedObjectId referenceKey="ObjectId_Street-1-AS_DRAINED--en-sz2-hi-FAMS-4-ONZ" />
        <RelatedObjectId referenceKey="ObjectId_Street-1-AS_DRAINED--en-sz2-hi-FAMS-5-OZA" />
     </RelatedObjectIds>
  </Relationship>
</RelationshipData>
</CatalogObjectId>

当第一个和第二个可选组不存在时,输出将有 4 条记录。

<?xml version="1.0" encoding="UTF-8"?>
<CatalogObjectId>
<RelationshipData>
  <Relationship>
     <RelationType>ObjectId_Street</RelationType>
     <RelatedObjectIds>
        <RelatedObjectId referenceKey="ObjectId_Street-1-AS_DRAINED--en--en-FAT-2-ONZ" />
        <RelatedObjectId referenceKey="ObjectId_Street-1-AS_DRAINED--en--en-FAT-3-OZA" />
        <RelatedObjectId referenceKey="ObjectId_Street-1-AS_DRAINED--en--en-FAMS-4-ONZ" />
        <RelatedObjectId referenceKey="ObjectId_Street-1-AS_DRAINED--en--en-FAMS-5-OZA" />
     </RelatedObjectIds>
  </Relationship>
</RelationshipData>
</CatalogObjectId>

【问题讨论】:

  • 当可选的 不存在时,您的预期输出是什么?

标签: xml xslt xslt-1.0 xslt-2.0 xslt-grouping


【解决方案1】:

好的。我不确定我是否完全理解您的预期输出。您的示例列出了 4 个可选循环,而不是两个,我不确定您的示例输出中缺少组的“en”来自哪里。

但是,这可以帮助您入门。我没有尝试在嵌套的 for-each 结构中汇总所有内容,而是在类似于递归下降解析器的结构中使用了多个模板。在每一层,代码都会检查可选元素并围绕它们循环,或者跳到下一层。 referenceKey-strings 作为参数传递并在我们向下时构建。

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

    <xsl:output method="xml" indent="yes"/>

    <xsl:template match="/document">
        <CatalogObjectId>
            <RelationshipData>
                <Relationship>
                    <RelationType>ObjectId_Street</RelationType>
                    <RelatedObjectIds>
                        <xsl:for-each select="ObjectId/dlex/attrGroupMany[@name='streetinfo']">
                            <xsl:variable name="pos" select="position()"/>
                            <xsl:apply-templates select="row" mode="streetintake">
                                <xsl:with-param name="referenceKey" select="concat('ObjectId_Street-',$pos)" />
                            </xsl:apply-templates>
                        </xsl:for-each>
                    </RelatedObjectIds>
                </Relationship>
            </RelationshipData>
        </CatalogObjectId>
    </xsl:template>

    <xsl:template match="row" mode="streetintake">
        <xsl:param name="referenceKey" />
        <xsl:variable name="streetcode" select="concat($referenceKey,'-',attr[@name='streetcode'],'-')"/>
        <xsl:choose>
            <xsl:when test="attrQualMany[@name='streetintake']/value">
                <xsl:for-each select="attrQualMany[@name='streetintake']/value">
                    <xsl:apply-templates select="../.." mode="streetsize">
                        <xsl:with-param name="referenceKey" select="concat($streetcode,text(),'-',@qual)" />
                    </xsl:apply-templates>
                </xsl:for-each>
            </xsl:when>
            <xsl:otherwise>
                <xsl:apply-templates select="." mode="streetsize">
                    <xsl:with-param name="referenceKey" select="$streetcode" />
                </xsl:apply-templates>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>

    <xsl:template match="row" mode="streetsize">
        <xsl:param name="referenceKey" />
        <xsl:choose>
            <xsl:when test="attrQualMany[@name='streetsizeDescription']/value">
                <xsl:for-each select="attrQualMany[@name='streetsizeDescription']/value">
                    <xsl:apply-templates select="../../attrGroupMany[@name='streetDetails']" mode="streetdetails">
                        <xsl:with-param name="referenceKey" select="concat($referenceKey,'-',text(),'-',@qual)" />
                    </xsl:apply-templates>
                </xsl:for-each>
            </xsl:when>
            <xsl:otherwise>
                <xsl:apply-templates select="attrGroupMany[@name='streetDetails']" mode="streetdetails">
                    <xsl:with-param name="referenceKey" select="$referenceKey" />
                </xsl:apply-templates>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>

    <xsl:template match="attrGroupMany" mode="streetdetails">
        <xsl:param name="referenceKey" />
        <xsl:choose>
            <xsl:when test="row">
                <xsl:apply-templates select="row" mode="streetdetails">
                    <xsl:with-param name="referenceKey" select="concat($referenceKey,'-',row/attr[@name='streetTypeCode'])" />
                </xsl:apply-templates>
            </xsl:when>
            <xsl:otherwise>
                <xsl:call-template name="RelatedObjectId">
                    <xsl:with-param name="referenceKey" select="$referenceKey" />
                </xsl:call-template>
            </xsl:otherwise>
        </xsl:choose>        
    </xsl:template>

    <xsl:template match="row" mode="streetdetails">
        <xsl:param name="referenceKey" />
        <xsl:choose>
            <xsl:when test="attrQualMany[@name='streetContained']">
                <xsl:apply-templates select="attrQualMany[@name='streetContained']">
                    <xsl:with-param name="referenceKey" select="$referenceKey"/>
                </xsl:apply-templates>
            </xsl:when>
            <xsl:otherwise>
                <xsl:call-template name="RelatedObjectId">
                    <xsl:with-param name="referenceKey" select="$referenceKey" />
                </xsl:call-template>
            </xsl:otherwise>
        </xsl:choose>        
    </xsl:template>

    <xsl:template match="attrQualMany[@name='streetContained']">
        <xsl:param name="referenceKey" />
        <xsl:choose>
            <xsl:when test="value">
                <xsl:for-each select="value">
                    <xsl:call-template name="RelatedObjectId">
                        <xsl:with-param name="referenceKey" select="concat($referenceKey,'-',text(),'-',@qual)" />
                    </xsl:call-template>
                </xsl:for-each>
            </xsl:when>
            <xsl:otherwise>
                <xsl:call-template name="RelatedObjectId">
                    <xsl:with-param name="referenceKey" select="$referenceKey" />
                </xsl:call-template>                
            </xsl:otherwise>
        </xsl:choose>        
    </xsl:template>

    <xsl:template name="RelatedObjectId">
        <xsl:param name="referenceKey" />
        <RelatedObjectId>
            <xsl:attribute name="referenceKey"><xsl:value-of select="$referenceKey"/></xsl:attribute>
        </RelatedObjectId>        
    </xsl:template>

</xsl:stylesheet>

【讨论】:

    【解决方案2】:

    我在现有代码中添加了更多的 sn-ps,以在所有可选组都丢失或完整时处理 null 场景

      <attrGroupMany name="streetDetails"> details are missing.
    

    <xsl:output method="xml" indent="yes"/>
    
    <xsl:template match="/document">
        <CatalogObjectId>
            <RelationshipData>
                <Relationship>
                    <RelationType>ObjectId_Street</RelationType>
                    <RelatedObjectIds>
                        <xsl:for-each select="ObjectId/dlex/attrGroupMany[@name='streetinfo']">
                            <xsl:variable name="pos" select="position()"/>
                            <xsl:apply-templates select="row" mode="streetintake">
                                <xsl:with-param name="referenceKey" select="concat('ObjectId_Street-',$pos)" />
                            </xsl:apply-templates>
                        </xsl:for-each>
                    </RelatedObjectIds>
                </Relationship>
            </RelationshipData>
        </CatalogObjectId>
    </xsl:template>
    
    <xsl:template match="row" mode="streetintake">
        <xsl:param name="referenceKey" />
        <xsl:variable name="streetcode" select="concat($referenceKey,'-',attr[@name='streetcode'],'-')"/>
        <xsl:choose>
            <xsl:when test="attrQualMany[@name='streetintake']/value">
                <xsl:for-each select="attrQualMany[@name='streetintake']/value">
                    <xsl:apply-templates select="../.." mode="streetsize">
                        <xsl:with-param name="referenceKey" select="concat($streetcode,text(),'-',@qual)" />
                    </xsl:apply-templates>
                </xsl:for-each>
            </xsl:when>
            <xsl:otherwise>
                <xsl:apply-templates select="." mode="streetsize">
                    <xsl:with-param name="referenceKey" select="$streetcode" />
                </xsl:apply-templates>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>
    
    <xsl:template match="row" mode="streetsize">
        <xsl:param name="referenceKey" />
        <xsl:choose>
            <xsl:when test="attrQualMany[@name='streetsizeDescription']/value">
                <xsl:choose>
                    <xsl:when test="attrGroupMany[@name='streetDetails']">
                        <xsl:for-each select="attrQualMany[@name='streetsizeDescription']/value">
                            <xsl:apply-templates select="../../attrGroupMany[@name='streetDetails']" mode="streetdetails">
                                <xsl:with-param name="referenceKey" select="concat($referenceKey,'-',text(),'-',@qual)" />
                            </xsl:apply-templates> 
                        </xsl:for-each>
                    </xsl:when>
                    <xsl:otherwise>
                        <xsl:for-each select="attrQualMany[@name='streetsizeDescription']/value">
                            <xsl:call-template name="RelatedObjectId">
                                <xsl:with-param name="referenceKey" select="concat($referenceKey,'-',text(),'-',@qual)" />
                            </xsl:call-template>   
                        </xsl:for-each>
                    </xsl:otherwise>
                </xsl:choose>
            </xsl:when>
            <xsl:otherwise>
                <xsl:if test="not(attrQualMany[@name='streetintake']) and not(attrQualMany[@name='streetsizeDescription']) and not(attrGroupMany[@name='streetDetails'])">
                    <xsl:call-template name="RelatedObjectId">
                        <xsl:with-param name="referenceKey" select="$referenceKey" />
                    </xsl:call-template>                
                </xsl:if>
                <xsl:apply-templates select="attrGroupMany[@name='streetDetails']" mode="streetdetails">
                    <xsl:with-param name="referenceKey" select="$referenceKey" />
                </xsl:apply-templates>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>
    
    <xsl:template match="attrGroupMany" mode="streetdetails">
        <xsl:param name="referenceKey" />
        <xsl:choose>
            <xsl:when test="row">
                <xsl:apply-templates select="row" mode="streetdetails">
                    <xsl:with-param name="referenceKey" select="concat($referenceKey,'-',row/attr[@name='streetTypeCode'])" />
                </xsl:apply-templates>
            </xsl:when>
            <xsl:otherwise>
                <xsl:call-template name="RelatedObjectId">
                    <xsl:with-param name="referenceKey" select="$referenceKey" />
                </xsl:call-template>
            </xsl:otherwise>
        </xsl:choose>        
    </xsl:template>
    
    <xsl:template match="row" mode="streetdetails">
        <xsl:param name="referenceKey" />
        <xsl:choose>
            <xsl:when test="attrQualMany[@name='streetContained']">
                <xsl:apply-templates select="attrQualMany[@name='streetContained']">
                    <xsl:with-param name="referenceKey" select="$referenceKey"/>
                </xsl:apply-templates>
            </xsl:when>
            <xsl:otherwise>
                <xsl:call-template name="RelatedObjectId">
                    <xsl:with-param name="referenceKey" select="$referenceKey" />
                </xsl:call-template>
            </xsl:otherwise>
        </xsl:choose>        
    </xsl:template>
    
    <xsl:template match="attrQualMany[@name='streetContained']">
        <xsl:param name="referenceKey" />
        <xsl:choose>
            <xsl:when test="value">
                <xsl:for-each select="value">
                    <xsl:call-template name="RelatedObjectId">
                        <xsl:with-param name="referenceKey" select="concat($referenceKey,'-',text(),'-',@qual)" />
                    </xsl:call-template>
                </xsl:for-each>
            </xsl:when>
            <xsl:otherwise>
                <xsl:call-template name="RelatedObjectId">
                    <xsl:with-param name="referenceKey" select="$referenceKey" />
                </xsl:call-template>                
            </xsl:otherwise>
        </xsl:choose>        
    </xsl:template>
    
    <xsl:template name="RelatedObjectId">
        <xsl:param name="referenceKey" />
        <RelatedObjectId>
            <xsl:attribute name="referenceKey">
                <xsl:value-of select="$referenceKey"/>
            </xsl:attribute>
        </RelatedObjectId>        
    </xsl:template>
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-04-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-09-25
      • 1970-01-01
      相关资源
      最近更新 更多