如何将带@属性与__text的JSON转回XML并恢复属性?(数组问题)
问题:将通过
writeAttributes=true转换的JSON转回XML并恢复所有属性 背景:XML转JSON的过程
使用DataWeave的writeAttributes=true属性可将XML转换为保留属性的JSON,规则为:用@key表示XML属性,__text表示元素的文本值。具体示例如下:
原始XML
<family surname="Simpsons"> <father age="42">Homer</father> <mother age="41">Marge</mother> <children> <child age="9">Bart</child> <child age="8">Lisa</child> <child age="1">Maggie</child> </children> </family>
转换用DataWeave代码
%dw 2.0 output application/json writeAttributes=true, duplicateKeyAsArray=true --- payload
转换后的JSON
{ "family": { "@surname": "Simpsons", "father": { "@age": "42", "__text": "Homer" }, "mother": { "@age": "41", "__text": "Marge" }, "children": { "child": [ { "@age": "9", "__text": "Bart" }, { "@age": "8", "__text": "Lisa" }, { "@age": "1", "__text": "Maggie" } ] } } }
反向转换遇到的问题
将上述JSON转回XML时,尝试使用以下DataWeave代码,发现数组中的<child>元素的age属性未能恢复:
尝试的DataWeave代码
%dw 2.0 output application/xml fun getAttributes(x) = x match { case is Object -> x filterObject ($$ as String startsWith "@") mapObject ((value, key, index) -> (key[1 to -1] ): value) else -> $ } fun convertToAttributes(x) = x match { case is Object -> x filterObject !($$ as String startsWith "@") mapObject ($$) @((getAttributes($))): convertToAttributes($) case is Array -> x map convertToAttributes($) else -> $ } --- convertToAttributes(payload)
转换后的XML(属性缺失)
<?xml version='1.0' encoding='UTF-8'?> <family surname="Simpsons"> <father age="42">Homer</father> <mother age="41">Marge</mother> <children> <child>Bart</child> <child>Lisa</child> <child>Maggie</child> </children> </family>
正确的解决方案
原代码问题在于处理数组元素时,未正确提取每个数组元素对象中的属性。修正后的代码需确保数组中的每个对象都能正确解析属性:
修正后的DataWeave代码
%dw 2.0 output application/xml fun extractAttributes(obj) = obj filterObject ((value, key) -> (key as String startsWith "@")) mapObject ((value, key) -> (key[1 to -1]): value) fun convertNode(node) = node match { case is Object -> // 分离属性、文本值和子节点 nonAttrNodes = node filterObject ((value, key) -> !(key as String startsWith "@") and key != "__text") textValue = node."__text" default null attributes = extractAttributes(node) // 处理非属性节点 nonAttrNodes mapObject ((value, key) -> (key) @(attributes): convertNode(value) ) // 无节点但有文本值时,直接返回文本 ++ (if (isEmpty(nonAttrNodes) and textValue != null) textValue else {}) case is Array -> node map convertNode($) else -> node } --- convertNode(payload)
转换后的正确XML
<?xml version='1.0' encoding='UTF-8'?> <family surname="Simpsons"> <father age="42">Homer</father> <mother age="41">Marge</mother> <children> <child age="9">Bart</child> <child age="8">Lisa</child> <child age="1">Maggie</child> </children> </family>
代码说明
extractAttributes函数:从对象中提取以@开头的属性,去掉前缀后转为XML属性格式。convertNode函数:递归处理每个节点:- 处理对象时,分离属性、文本值与子节点,将属性附加到对应XML元素上;
- 处理数组时,遍历每个元素并递归解析,确保数组元素的属性被正确识别;
- 处理
__text值,当元素无任何子节点时,直接将其作为元素文本。
内容的提问来源于stack exchange,提问作者Tony
相关产品推荐
相关产品推荐

