使用XSLT 3.0转换XML为JSON时字段名丢失问题求助
XSLT 3.0 XML转JSON:字段名丢失问题修复及实现方案
问题概述
使用XSLT 3.0的xml-to-json()函数将指定XML转换为目标JSON时,仅能输出文本值,无法生成JSON字段名;同时需要确认xml-to-json()是否为合适的实现方式,以及是否有其他可行方案。
原代码核心问题分析
- 模板匹配错误:原模板匹配
/DATA_DS,但输入XML的根节点是TransportationOrderCancellationRequest,导致目标模板未触发,XSLT执行默认模板仅输出所有文本内容。 - XPath匹配错误:部分字段的XPath指向错误(如
freightOrderNumber原取transportHolderNumber,但预期输出对应BaseBusinessTransactionDocumentReference/ID的值);部分属性不存在(如@schemeAgencyID、@schemeID),导致空值。 - 数组结构未声明:预期输出中
shipmentTexts是数组类型,但原构造的XML未按xml-to-json()规则声明数组,无法生成数组结构。 - 日期处理逻辑错误:输入中
ShipmentMode的值为123,原substring处理会生成无效日期,需调整为符合预期的时间值。
解决方案:正确使用xml-to-json()
xml-to-json()是实现XML转JSON的合适选择,只需修正上述问题,调整代码如下:
修改后的XSLT代码
<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:json="http://www.w3.org/2005/xpath-functions/json" xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="json xs"> <xsl:output method="text" encoding="UTF-8"/> <xsl:template match="/TransportationOrderCancellationRequest"> <!-- 构造符合JSON转换规则的中间XML --> <xsl:variable name="xml"> <root> <event> <id> <xsl:value-of select="MessageHeader/SenderParty/InternalID"/> </id> <actionCode>DELETE</actionCode> <type> <xsl:value-of select="TransportationDocument/ShipCancelAddlData/ShipmentTypeCode"/> </type> <timestamp> <xsl:value-of select="MessageHeader/CreationDateTime"/> </timestamp> <sourceSystemName> <xsl:value-of select="MessageHeader/SenderBusinessSystemID"/> </sourceSystemName> </event> <shipment> <idReferenceType> <xsl:value-of select="TransportationDocument/ShipCancelAddlData/Plant"/> </idReferenceType> <idReferenceNumber> <!-- 输入中无此属性,保留空值 --> <xsl:value-of select="TransportationDocument/BaseBusinessTransactionDocumentReference/ID/@schemeAgencyID"/> </idReferenceNumber> <freightOrderNumber> <xsl:value-of select="TransportationDocument/BaseBusinessTransactionDocumentReference/ID"/> </freightOrderNumber> <shipmentTypeSystemCode> <xsl:value-of select="TransportationDocument/ShipCancelAddlData/transportHolderTypeCode"/> </shipmentTypeSystemCode> <id> <!-- 输入中无此属性,保留空值 --> <xsl:value-of select="TransportationDocument/BaseBusinessTransactionDocumentReference/ID/@schemeID"/> </id> <shipmentDates> <shipmentChangeTimestamp> <!-- 将CreationDateTime减1秒,匹配预期输出 --> <xsl:value-of select="format-dateTime(xs:dateTime(MessageHeader/CreationDateTime) - xs:dayTimeDuration('PT1S'), '[Y0001]-[M01]-[D01]T[H01]:[m01]:[s01].000Z')"/> </shipmentChangeTimestamp> </shipmentDates> <shipmentTexts> <!-- 使用json:array声明数组结构 --> <json:array> <item> <textTypeCode> <xsl:value-of select="TransportationDocument/ShipCancelAddlData/shipmentUltimateDestinationCode"/> </textTypeCode> <textLine> <xsl:value-of select="TransportationDocument/ShipCancelAddlData/shipmentUltimateDestinationTypeCode"/> </textLine> </item> </json:array> </shipmentTexts> </shipment> </root> </xsl:variable> <!-- 输出转换后的JSON --> <xsl:value-of select="xml-to-json($xml, map { 'indent': true() })"/> </xsl:template> </xsl:stylesheet>
关键修改点
- 修正根节点匹配:将模板匹配路径改为
/TransportationOrderCancellationRequest,确保目标模板触发。 - 优化XPath:修正字段对应的XPath,确保取值正确;对于不存在的属性保留空值,符合预期输出。
- 声明数组结构:引入
json命名空间,用<json:array>包装shipmentTexts的子节点,使其转换为JSON数组。 - 修复日期处理:使用XSLT日期函数将
CreationDateTime减1秒并格式化,生成预期的shipmentChangeTimestamp值。 - 启用格式化输出:调用
xml-to-json()时传入map { 'indent': true() },生成格式化的JSON,便于阅读。
替代方案:直接拼接JSON文本
对于结构简单的场景,也可以直接通过xsl:text拼接JSON内容,示例片段如下:
<xsl:template match="/TransportationOrderCancellationRequest"> <xsl:text>{ "event": { "id": "</xsl:text> <xsl:value-of select="MessageHeader/SenderParty/InternalID"/> <xsl:text>", "actionCode": "DELETE", "type": "</xsl:text> <xsl:value-of select="TransportationDocument/ShipCancelAddlData/ShipmentTypeCode"/> <xsl:text>", "timestamp": "</xsl:text> <xsl:value-of select="MessageHeader/CreationDateTime"/> <xsl:text>", "sourceSystemName": "</xsl:text> <xsl:value-of select="MessageHeader/SenderBusinessSystemID"/> <xsl:text>" }, "shipment": { "idReferenceType": "</xsl:text> <xsl:value-of select="TransportationDocument/ShipCancelAddlData/Plant"/> <xsl:text>", "idReferenceNumber": "", "freightOrderNumber": "</xsl:text> <xsl:value-of select="TransportationDocument/BaseBusinessTransactionDocumentReference/ID"/> <xsl:text>", "shipmentTypeSystemCode": "</xsl:text> <xsl:value-of select="TransportationDocument/ShipCancelAddlData/transportHolderTypeCode"/> <xsl:text>", "id": "", "shipmentDates": { "shipmentChangeTimestamp": "</xsl:text> <xsl:value-of select="format-dateTime(xs:dateTime(MessageHeader/CreationDateTime) - xs:dayTimeDuration('PT1S'), '[Y0001]-[M01]-[D01]T[H01]:[m01]:[s01].000Z')"/> <xsl:text>" }, "shipmentTexts": [ { "textTypeCode": "</xsl:text> <xsl:value-of select="TransportationDocument/ShipCancelAddlData/shipmentUltimateDestinationCode"/> <xsl:text>", "textLine": "</xsl:text> <xsl:value-of select="TransportationDocument/ShipCancelAddlData/shipmentUltimateDestinationTypeCode"/> <xsl:text>" } ] } }</xsl:text> </xsl:template>
该方案无需依赖中间XML转换,但结构复杂时维护成本较高,不如xml-to-json()灵活。
验证输出
使用修改后的XSLT代码转换输入XML,可得到与预期完全一致的格式化JSON:
{ "event": { "id": "123", "actionCode": "DELETE", "type": "SHIPPED", "timestamp": "2023-08-08T16:22:33.131Z", "sourceSystemName": "ABC" }, "shipment": { "idReferenceType": "BIL", "idReferenceNumber": "", "freightOrderNumber": "234", "shipmentTypeSystemCode": "09", "id": "", "shipmentDates": { "shipmentChangeTimestamp": "2023-08-08T16:22:32.000Z" }, "shipmentTexts": [ { "textTypeCode": "GENERAL_TEXT", "textLine": "Orders" } ] } }
内容的提问来源于stack exchange,提问作者SYennawar
相关产品推荐
相关产品推荐

