XSLT2.0转换嵌套XML为带属性元素:LocationDetails转换异常求助
解决XSLT转换中LocationDetails元素错误转为属性的问题
源XML
<?xml version="1.0" encoding="UTF-8" ?> <Document xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <StartOfTransmission> <SenderId>SENDERSID</SenderId> <ReceiverId>RECEIVERSID</ReceiverId> <TRANSDATE>13-09-2010</TRANSDATE> <TRANSTIME>12:00:00</TRANSTIME> <SenderReference>1234</SenderReference> <ReceiverReference/> <ApplicationReference>ORDHDR</ApplicationReference> </StartOfTransmission> <FileDetails> <GenerationNumber>12344</GenerationNumber> <VersionNumber>0001</VersionNumber> <FileCreationDate>25-04-2008</FileCreationDate> </FileDetails> <Order> <OrderHeader> <OrderDate>13-09-2010</OrderDate> <OrderTime>16:00:00</OrderTime> <OrderReference>Order Ref1</OrderReference> <RetailerId>132</RetailerId> <LocationDetails> <ANACode>5013546167507</ANACode> <CustomerLocationCode>16750</CustomerLocationCode> </LocationDetails> </OrderHeader> </Order> </Document>
目标转换格式
<?xml version="1.0" encoding="UTF-8"?> <a:Document xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://127.0.0.1:8080 http://127.0.0.1:8080/tbattributesxml2.xsd" xmlns:a="http://127.0.0.1:8080"> <a:StartOfTransmission SenderId="SENDERSID" ReceiverId="RECEIVERSID" transdatetime="2010-09-13T12:00:00.000" SenderReference="1234" ReceiverReference="" ApplicationReference="ORDHDR"/> <a:FileDetails GenerationNumber="12344" VersionNumber="0001" FileCreationDate="2008-04-25T00:00:00.000"/> <a:Order> <a:OrderHeader orderdate="2010-09-13T16:00:00.000" OrderReference="Order Ref1" RetailerId="132" DeliveryType="CARR" BackOrderFlag="N" OrderType="B" InternetOrderReference="Internet Ref"> <a:LocationDetails ANACode="5013546167507" CustomerLocationCode="16750"/> </a:OrderHeader> </a:Order> </a:Document>
当前使用的XSLT样式表
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:saxon="http://saxon.sf.net/" xmlns:a="http://127.0.0.1:8080" exclude-result-prefixes="xs" version="2.0" > <xsl:output method="xml" indent="no" /> <xsl:strip-space elements="*"/> <xsl:template match="Document" > <xsl:text>
</xsl:text> <a:Document xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://127.0.0.1:8080 http://127.0.0.1:8080/test/tbattributesxml2.xsd"> <xsl:apply-templates/> </a:Document> </xsl:template> <xsl:template match="StartOfTransmission"> <xsl:text>
	</xsl:text> <a:StartOfTransmission transdatetime="{replace(TRANSDATE, '(.{2})-(.{2})-(.{4})', '$3-$2-$1')}T{TRANSTIME}"> <xsl:apply-templates select="* except(TRANSDATE, TRANSTIME)"/> </a:StartOfTransmission> </xsl:template> <xsl:template match="StartOfTransmission/*"> <xsl:attribute name="{name()}" select="."/> </xsl:template> <xsl:template match="FileDetails"> <xsl:text>
	</xsl:text> <xsl:variable name="dte" as="xs:string"> <xsl:value-of select="concat(substring(FileCreationDate, 7, 4), '-', substring(FileCreationDate, 4, 2), '-', substring(FileCreationDate, 1, 2))"/> </xsl:variable> <xsl:variable name="dateTime" select="concat($dte,'T','00:00:00.000')"/> <a:FileDetails FileCreationDate="{$dateTime}"> <xsl:apply-templates select="* except(FileCreationDate)"/> </a:FileDetails> </xsl:template> <xsl:template match="FileDetails/*"> <xsl:attribute name="{name()}" select="."/> </xsl:template> <xsl:template match="Order"> <xsl:text>
	</xsl:text> <a:Order> <xsl:apply-templates select="*" /> <xsl:text>
	</xsl:text> </a:Order> </xsl:template> <xsl:template match="OrderHeader"> <xsl:text>
		</xsl:text> <a:OrderHeader > <xsl:apply-templates select="*"/> </a:OrderHeader> </xsl:template> <xsl:template match="OrderHeader/*"> <xsl:attribute name="{name()}" select="."/> </xsl:template> <xsl:template match="LocationDetails"> <xsl:text>
			</xsl:text> <a:LocationDetails> <xsl:apply-templates select="ANACode"/> </a:LocationDetails> </xsl:template> <xsl:template match="LocationDetails/*"> <xsl:attribute name="{name()}" select="*"/> </xsl:template> </xsl:stylesheet>
错误输出
<?xml version="1.0" encoding="UTF-8"?> <a:Document xmlns:a="http://127.0.0.1:8080" xmlns:saxon="http://saxon.sf.net/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://127.0.0.1:8080 http://127.0.0.1:8080/test/tbattributesxml2.xsd"> <a:StartOfTransmission transdatetime="2010-09-13T12:00:00" SenderId="SENDERSID" ReceiverId="RECEIVERSID" SenderReference="1234" ReceiverReference="" ApplicationReference="ORDHDR"/> <a:FileDetails FileCreationDate="2008-04-25T00:00:00.000" GenerationNumber="12344" VersionNumber="0001"/> <a:Order> <a:OrderHeader OrderDate="13-09-2010" OrderTime="16:00:00" OrderReference="Order Ref1" RetailerId="132" LocationDetails="501354616750716750"/> </a:Order></a:Document>
问题分析与修复方案
问题原因
OrderHeader/*模板会匹配OrderHeader下的所有子元素,包括LocationDetails,将其直接转换为OrderHeader的属性,覆盖了LocationDetails自身的模板逻辑LocationDetails模板仅处理了ANACode子元素,遗漏了CustomerLocationCodeLocationDetails/*模板中属性值选取错误(select="*"会选取子元素而非当前元素的值)
修复后的XSLT样式表
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:saxon="http://saxon.sf.net/" xmlns:a="http://127.0.0.1:8080" exclude-result-prefixes="xs" version="2.0" > <xsl:output method="xml" indent="no" /> <xsl:strip-space elements="*"/> <xsl:template match="Document" > <xsl:text>
</xsl:text> <a:Document xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://127.0.0.1:8080 http://127.0.0.1:8080/test/tbattributesxml2.xsd"> <xsl:apply-templates/> </a:Document> </xsl:template> <xsl:template match="StartOfTransmission"> <xsl:text>
	</xsl:text> <a:StartOfTransmission transdatetime="{replace(TRANSDATE, '(.{2})-(.{2})-(.{4})', '$3-$2-$1')}T{TRANSTIME}"> <xsl:apply-templates select="* except(TRANSDATE, TRANSTIME)"/> </a:StartOfTransmission> </xsl:template> <xsl:template match="StartOfTransmission/*"> <xsl:attribute name="{name()}" select="."/> </xsl:template> <xsl:template match="FileDetails"> <xsl:text>
	</xsl:text> <xsl:variable name="dte" as="xs:string"> <xsl:value-of select="concat(substring(FileCreationDate, 7, 4), '-', substring(FileCreationDate, 4, 2), '-', substring(FileCreationDate, 1, 2))"/> </xsl:variable> <xsl:variable name="dateTime" select="concat($dte,'T','00:00:00.000')"/> <a:FileDetails FileCreationDate="{$dateTime}"> <xsl:apply-templates select="* except(FileCreationDate)"/> </a:FileDetails> </xsl:template> <xsl:template match="FileDetails/*"> <xsl:attribute name="{name()}" select="."/> </xsl:template> <xsl:template match="Order"> <xsl:text>
	</xsl:text> <a:Order> <xsl:apply-templates select="*" /> <xsl:text>
	</xsl:text> </a:Order> </xsl:template> <xsl:template match="OrderHeader"> <xsl:text>
		</xsl:text> <a:OrderHeader > <!-- 应用模板时排除LocationDetails,让其使用自身模板 --> <xsl:apply-templates select="* except(LocationDetails)"/> <!-- 单独处理LocationDetails --> <xsl:apply-templates select="LocationDetails"/> </a:OrderHeader> </xsl:template> <!-- 修改匹配模式,排除LocationDetails,避免将其转为属性 --> <xsl:template match="OrderHeader/*[not(self::LocationDetails)]"> <xsl:attribute name="{name()}" select="."/> </xsl:template> <xsl:template match="LocationDetails"> <xsl:text>
			</xsl:text> <a:LocationDetails> <!-- 处理所有子元素,包括ANACode和CustomerLocationCode --> <xsl:apply-templates select="*"/> </a:LocationDetails> </xsl:template> <!-- 修正属性值选取逻辑,取当前元素的值 --> <xsl:template match="LocationDetails/*"> <xsl:attribute name="{name()}" select="."/> </xsl:template> </xsl:stylesheet>
修复说明
- 修改
OrderHeader模板:在apply-templates时排除LocationDetails,并单独调用其模板,确保LocationDetails作为独立元素生成 - 调整
OrderHeader/*的匹配模式,添加[not(self::LocationDetails)],避免将LocationDetails转换为属性 - 更新
LocationDetails模板的apply-templates范围为*,确保所有子元素都被处理 - 修正
LocationDetails/*模板的属性值选取为select=".",正确获取当前元素的文本内容作为属性值
内容的提问来源于stack exchange,提问作者blm99
相关产品推荐
相关产品推荐

