使用标记化参数和父上下文调用 XSLT 模板
Call XSLT template with tokenized parameter and parent context
能否设置对 XSLT 模板的调用,使其与当前上下文的父级一起调用?
我的 XML 与具有 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 方法。
您可以通过将值存储在变量中来实现,如:
<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>
XSLT/XPath 中的一个常见习语,只处理两个可能元素中的第一个是构建一个序列,select 该序列中的第一个项目,即对于你的情况 select ((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>
并删除 xsl:stylesheet
、http://xsltransform.hikmatu.com/eiQZDbi
上的 expand-text
属性
能否设置对 XSLT 模板的调用,使其与当前上下文的父级一起调用?
我的 XML 与具有 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 方法。
您可以通过将值存储在变量中来实现,如:
<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>
XSLT/XPath 中的一个常见习语,只处理两个可能元素中的第一个是构建一个序列,select 该序列中的第一个项目,即对于你的情况 select ((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>
并删除 xsl:stylesheet
、http://xsltransform.hikmatu.com/eiQZDbi
expand-text
属性