微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

使用 xmltodict 从 XML 为有时重复的元素生成一致的 JSON

如何解决使用 xmltodict 从 XML 为有时重复的元素生成一致的 JSON

对于使用 python 将 XML 转换为 JSON,存在几种方法,它们通常归结为相同的原理。今天提到最多的方法是xmltodict。

我正在尝试将多个 xml 文档转换为 JSON,但遇到问题如果在某些文档中重复的元素出现一次在这些情况下,生成的不是列表而是对象.这种不一致会导致在例如 spark 中摄取 JSON 时出现问题,它无法再推断 json 元素的架构(元素是列表还是字符串?)并将其转换为字符串。 我们怎样才能最好地解决这个问题?理想情况下,解析器会采用模式 (XSD) 并“了解”元素可以是无限的,因此应该是一个列表,即使它们是单独的。

  1. 是否有使用 XSD 将 XML 转换为 JSON 的方法
  2. 是否有其他可能的解决方法?例如,我正在考虑将每个非列表项放入一个列表中,但这会产生开销。

这是一些显示问题的代码

import xmltodict
from lxml import etree

xml1="""<?xml version="1.0" encoding="UTF-8"?>
<a xmlns="https://some.com/ns" xsi:schemaLocation="https://some.com/ns schema.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><b>x</b></a>
"""
xml2="""<?xml version="1.0" encoding="UTF-8"?>
<a xmlns="https://some.com/ns" xsi:schemaLocation="https://some.com/ns schema.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><b>x</b><b>y</b></a>
"""
xsd="""<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns="https://some.com/ns" targetNamespace="https://some.com/ns"  elementFormDefault="qualified" attributeFormDefault="qualified" version="2.4">
    <xs:element name="a" type="aType"/>
    <xs:complexType name="aType">
        <xs:sequence>
            <xs:element name="b" type="xs:string" maxOccurs="unbounded"/>
        </xs:sequence>
    </xs:complexType>
</xs:schema>    
"""

print(json.dumps(xmltodict.parse(xml1),indent=True))
print(json.dumps(xmltodict.parse(xml2),indent=True))

xmlschema_doc = etree.fromstring(xsd.encode())
xmlschema = etree.XMLSchema(xmlschema_doc)


xml1_doc = etree.fromstring(xml1.encode())
print(etree.tostring(xml1_doc))
result1 = xmlschema.validate(xml1_doc)
print("validation xml1: ")
print(result1)

xml2_doc = etree.fromstring(xml2.encode())
result2 = xmlschema.validate(xml2_doc)
print("validation xml2: ")
print(result2)

将 xml1 输出为 JSON:

{
 "a": {
  "@xmlns": "https://some.com/ns","@xsi:schemaLocation": "https://some.com/ns schema.xsd","@xmlns:xsi": "http://www.w3.org/2001/XMLSchema-instance","b": "x"
 }
}

对于 xml2

{
 "a": {
  "@xmlns": "https://some.com/ns","b": [
   "x","y"
  ]
 }
}

解决方法可能是:

def nestit(path,key,value):
    # don't nest lists. also dont nest attributes.
    if type(value) == list or key[:1]=='@':
        return key,value
    else:
        return key,[value]

print(json.dumps(xmltodict.parse(xml1,postprocessor=nestit),indent=True))

产生:

{
 "a": [
  {
   "@xmlns": "https://some.com/ns","b": [
    "x"
   ]
  }
 ]
}

但在非常复杂的 xml 结构中,对于永不重复的元素,效率会降低。

解决方法

是否有使用 XSD 将 XML 转换为 JSON 的方法?

xmlschema 正是这样做的:

import xmlschema

schema = xmlschema.XMLSchema(xsd)
print(json.dumps(xmlschema.to_dict(xml1,schema=schema,preserve_root=True),indent=True))

返回:

{
 "a": {
  "@xmlns": "https://some.com/ns","@xmlns:xsi": "http://www.w3.org/2001/XMLSchema-instance","@xsi:schemaLocation": "https://some.com/ns schema.xsd","b": [
   "x"
  ]
 }
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。