XSLT模板应用问题求助:XML双节点转换输出异常
XSLT转换问题解决
问题描述
刚接触XSLT模板,需要编写转换处理包含<Common>和<ExtendedFields>两个节点(各含多个元素)的XML,但使用模板时遇到问题:尝试过多种模板写法,甚至把ExtendedFields的元素移到Common节点里,结果<OriginalFace>输出的却是ExtendedFields的所有值。附上相关代码及预期输出,寻求帮助。
现有代码
XSLT代码
<?xml version="1.0" encoding="ISO-8859-1"?> <xsl:stylesheet version="1.0" xmlns:k="urn:tradefeed-xsd" xmlns:ns0="http://OpenGeneva" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:dm="urn:DataMapping" > <xsl:template match="k:Field[@calcrt='DS122'][. = 'Mtge']"> <xsl:value-of select="k:TradeAmount"/> </xsl:template> <xsl:output method="xml" indent="yes"/> <xsl:template match="/"> <ns0:Root> <xsl:for-each select="//k:BatchFeed/k:TradeFeed/k:Common"> <Transaction> <OriginalFace><xsl:apply-templates select="//k:Common"/></OriginalFace> <Investment><xsl:value-of select="k:BloombergGlobalIdentifier"/></Investment> </Transaction> </xsl:for-each> </ns0:Root> </xsl:template> </xsl:stylesheet>
XML输入
<?xml version="1.0" encoding="UTF-8"?> <BatchFeed xmlns="urn:tradefeed-xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <TradeFeed> <Common> <TradeAmount>2000000.0</TradeAmount> <BloombergGlobalIdentifier>BBG01412S0N8</BloombergGlobalIdentifier> </Common> <ExtendedFields> <Field calcrt="DS122" name="MARKET_SECTOR_DES">Mtge</Field> </ExtendedFields> </TradeFeed> </BatchFeed>
预期输出
<?xml version="1.0" encoding="UTF-8"?> <ns0:Root xmlns:dm="urn:DataMapping" xmlns:k="urn:tradefeed-xsd" xmlns:ns0="http://OpenGeneva"> <Transaction> <OriginalFace>2000000.0</OriginalFace> <Investment>BBG01412S0N8</Investment> </Transaction> </ns0:Root>
问题分析与修正
原代码问题点
- 模板匹配未触发:你写的
k:Field模板从未被执行,因为<xsl:apply-templates>选择的是//k:Common,而Field节点在ExtendedFields下,不在Common节点范围内。 - 全局节点选择错误:
//k:Common是从根节点开始全局查找所有Common节点,且XSLT的默认模板会输出节点下所有文本内容,导致<OriginalFace>会输出Common里所有元素的文本(包括TradeAmount和BloombergGlobalIdentifier的值),不符合预期。 - 节点关联错误:原模板中
k:Field里选择k:TradeAmount是无效的,因为TradeAmount和Field是同级TradeFeed下的不同子节点,Field的上下文无法直接找到TradeAmount。
修正后的XSLT代码
<?xml version="1.0" encoding="ISO-8859-1"?> <xsl:stylesheet version="1.0" xmlns:k="urn:tradefeed-xsd" xmlns:ns0="http://OpenGeneva" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:dm="urn:DataMapping" > <xsl:output method="xml" indent="yes" encoding="UTF-8"/> <!-- 匹配根节点,遍历每个TradeFeed --> <xsl:template match="/"> <ns0:Root> <xsl:for-each select="//k:BatchFeed/k:TradeFeed"> <Transaction> <!-- 当ExtendedFields下的Field满足条件时,输出对应Common里的TradeAmount --> <OriginalFace> <xsl:if test="k:ExtendedFields/k:Field[@calcrt='DS122' and .='Mtge']"> <xsl:value-of select="k:Common/k:TradeAmount"/> </xsl:if> </OriginalFace> <Investment> <xsl:value-of select="k:Common/k:BloombergGlobalIdentifier"/> </Investment> </Transaction> </xsl:for-each> </ns0:Root> </xsl:template> </xsl:stylesheet>
修正说明
- 遍历TradeFeed而非Common:这样可以同时访问当前TradeFeed下的
Common和ExtendedFields节点,方便关联对应的数据。 - 直接条件判断取值:在
<OriginalFace>中直接判断当前TradeFeed下的Field是否符合要求,符合则输出同级Common里的TradeAmount,逻辑更直接清晰。 - 指定输出编码:添加
encoding="UTF-8"让输出编码与预期一致。
内容的提问来源于stack exchange,提问作者MagicWagon
相关产品推荐
相关产品推荐

