是否可以设置对XSLT模板的调用,以便使用当前上下文的父项调用它?
我的XML如下所示,Job节点有1个子位置节点:
<Job>
<JobId>12345</JobId>
<JobTitle>Programmer</JobTitle>
<Location>
<LocationCode>US</LocationCode>
<!-- there is a variable number of comma-deliminated strings within the sublocations node -->
<SubLocations>US1,US2,US3</SubLocations>
</Location>
<Location>
<LocationCode>CAN</LocationCode>
</Location>
</Job>
我希望每个位置的每个作业或子位置输出为单行:
<Id>12345</Id><Title>Programmer</Title><Location>US1</Location>
<Id>12345</Id><Title>Programmer</Title><Location>US2</Location>
<Id>12345</Id><Title>Programmer</Title><Location>US3</Location>
<Id>12345</Id><Title>Programmer</Title><Location>CAN</Location>
我的XSLT的核心逻辑如下:
<xsl:template match="Job/Location">
<xsl:choose>
<!-- Test for presence of sublocation -->
<xsl:when test="SubLocation != null">
<xsl:for-each select="distinct-values(SubLocation/tokenize(.,','))">
<xsl:call-template name="JobRecord">
<xsl:with-param name="Location">
<xsl:value-of select="."/>
</xsl:with-param>
</xsl:call-template>
</xsl:for-each>
</xsl:when>
<xsl:otherwise>
<!-- No Sublocation present -->
<xsl:call-template name="JobRecord">
<xsl:with-param name="Location">
<xsl:value-of select="/LocationCode"/>
</xsl:with-param>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="JobRecord">
<xsl:param name="Location"/>
<Id><xsl:value-of select="../JobId"/></Id>
<Name><xsl:value-of select="../JobTitle"/></Name>
<Location><xsl:value-of select="$Location"/></Location>
</xsl:template>
即使输出的内容位于作业节点级别,也需要按位置或子位置(如果适用)调用JobRecord模板。如何在不丢失父项的上下文的情况下拆分或迭代子位置?
解决方法是将所有作业级别信息作为参数传递,但我正在寻找更自然的XSLT方法。
答案 0 :(得分:1)
您可以通过将值存储在变量中来实现,如:
<xsl:variable name="JID" select="preceding-sibling::JobId"/>
<xsl:variable name="JTITLE" select="preceding-sibling::JobTitle"/>
并最终将它们作为命名模板中的参数传递。整个样式表如下。
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs"
version="2.0">
<xsl:strip-space elements="*"/>
<xsl:output indent="yes" omit-xml-declaration="yes"/>
<xsl:template match="Job/Location">
<xsl:variable name="JID" select="preceding-sibling::JobId"/>
<xsl:variable name="JTITLE" select="preceding-sibling::JobTitle"/>
<xsl:choose>
<xsl:when test="SubLocations != ''">
<xsl:for-each select="distinct-values(SubLocations/tokenize(.,','))">
<xsl:call-template name="JobRecord">
<xsl:with-param name="Location" select="."/>
<xsl:with-param name="JobID" select="$JID"/>
<xsl:with-param name="JobTITLE" select="$JTITLE"/>
</xsl:call-template>
</xsl:for-each>
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="JobRecord">
<xsl:with-param name="Location" select="LocationCode"/>
<xsl:with-param name="JobID" select="$JID"/>
<xsl:with-param name="JobTITLE" select="$JTITLE"/>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="JobRecord">
<xsl:param name="JobID"/>
<xsl:param name="JobTITLE"/>
<xsl:param name="Location"/>
<Id><xsl:value-of select="$JobID"/></Id>
<Name><xsl:value-of select="$JobTITLE"/></Name>
<Location><xsl:value-of select="$Location"/></Location>
</xsl:template>
<xsl:template match="JobId|JobTitle"/>
</xsl:stylesheet>
答案 1 :(得分:1)
XSLT / XPath中常见的习惯用法,只处理两个可能元素中的第一个,就是构造一个序列并选择该序列中的第一个项目,即你的情况选择((SubLocations, LocationCode)[1])
,就像那样你获取元素SubLocations
(如果存在)或其他元素LocationCode
。然后你可以标记化并将结果发送到另一个模板,而不是使用call-template
我只是建议将元素Job
推送到另一个与命名模式匹配的模板:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
expand-text="yes"
version="3.0">
<xsl:output omit-xml-declaration="yes"/>
<xsl:template match="Job">
<xsl:variable name="job" select="."/>
<xsl:for-each select="Location/tokenize((SubLocations, LocationCode)[1], ',')">
<xsl:apply-templates select="$job" mode="row">
<xsl:with-param name="loc" select="current()"/>
</xsl:apply-templates>
</xsl:for-each>
</xsl:template>
<xsl:template match="Job" mode="row">
<xsl:param name="loc"/>
<Id>{JobId}</Id>
<Title>{JobTitle}</Title>
<Location>{$loc}</Location>
<xsl:text> </xsl:text>
</xsl:template>
</xsl:stylesheet>
这是一个XSLT 3示例,使用Saxon 9.8所有版本,在http://xsltfiddle.liberty-development.net/bFukv8i联机,但当然,如果需要,可以通过将最后一个模板更改为
来适应XSLT 2 <xsl:template match="Job" mode="row">
<xsl:param name="loc"/>
<Id>
<xsl:value-of select="JobId"/>
</Id>
<Title>
<xsl:value-of select="JobTitle"/>
</Title>
<Location>
<xsl:value-of select="$loc"/>
</Location>
<xsl:text> </xsl:text>
</xsl:template>
并删除expand-text
,http://xsltransform.hikmatu.com/eiQZDbi
xsl:stylesheet
属性