我有一个示例消息,必须使用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>
好的。我不确定我是否完全理解你的预期产出。您的示例列出了4个可选循环,而不是两个,并且我不确定带有缺失组的示例输出中的"en"来自哪里。
然而,这可以让你开始。我没有尝试在嵌套的结构中为每个结构汇总所有内容,而是在类似于递归下降语法分析器的结构中使用了几个模板。在每个级别上,代码都会检查可选元素,并围绕它们循环,或者跳到下一个级别。referenceKey字符串是作为一个参数传递的,并在我们往下看的时候构建。
<?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>
我在现有代码中添加了一些片段,以在所有可选组丢失或完整时处理空场景
<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>