You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

XSDATA生成的Python模型无法解析单条Book数据,多条正常

问题

使用XSDATA工具结合JSON生成Python数据类模型时,出现解析异常:

  • 当books节点下包含多个book对象时,模型可正常将其解析为List[Book]类型;
  • 当books节点下仅存在单个book对象时,模型的book列表为空,无法读取该条数据。

相关代码示例

sample.xml

<?xml version="1.0"?>
<catalog>
    <books>
        <book id="bk101">
            <author>Gambardella, Matthew</author>
            <title>XML Developer's Guide</title>
            <genre>Computer</genre>
            <price>44.95</price>
            <publish_date>2000-10-01</publish_date>
            <description>An in-depth look at creating applications 
      with XML.</description>
        </book>
        <book id="bk101">
            <author>Gambardella, Matthew</author>
            <title>XML Developer's Guide</title>
            <genre>Computer</genre>
            <price>44.95</price>
            <publish_date>2000-10-01</publish_date>
            <description>An in-depth look at creating applications 
      with XML.</description>
        </book>
    </books>
</catalog>

多book的sample.json

{
    "catalog": {
        "books": {
            "book": [
                {
                    "@id": "bk101",
                    "author": "Gambardella, Matthew",
                    "title": "XML Developer's Guide",
                    "genre": "Computer",
                    "price": "44.95",
                    "publish_date": "2000-10-01",
                    "description": "An in-depth look at creating applications \n      with XML."
                },
                {
                    "@id": "bk101",
                    "author": "Gambardella, Matthew",
                    "title": "XML Developer's Guide",
                    "genre": "Computer",
                    "price": "44.95",
                    "publish_date": "2000-10-01",
                    "description": "An in-depth look at creating applications \n      with XML."
                }
            ]
        }
    }
}

单book的sample.json

{
    "catalog": {
        "books": {
            "book": {
                "@id": "bk101",
                "author": "Gambardella, Matthew",
                "title": "XML Developer's Guide",
                "genre": "Computer",
                "price": "44.95",
                "publish_date": "2000-10-01",
                "description": "An in-depth look at creating applications \n      with XML."
            }
        }
    }
}

models.py

from dataclasses import dataclass, field
from typing import List, Optional
from xsdata.models.datatype import XmlDate


@dataclass
class Book:
    class Meta:
        name = "book"

    id: Optional[str] = field(
        default=None,
        metadata={
            "name": "@id",
            "type": "Element",
        }
    )
    author: Optional[str] = field(
        default=None,
        metadata={
            "type": "Element",
        }
    )
    title: Optional[str] = field(
        default=None,
        metadata={
            "type": "Element",
        }
    )
    genre: Optional[str] = field(
        default=None,
        metadata={
            "type": "Element",
        }
    )
    price: Optional[float] = field(
        default=None,
        metadata={
            "type": "Element",
        }
    )
    publish_date: Optional[XmlDate] = field(
        default=None,
        metadata={
            "type": "Element",
        }
    )
    description: Optional[str] = field(
        default=None,
        metadata={
            "type": "Element",
        }
    )


@dataclass
class Books:
    class Meta:
        name = "books"

    book: List[Book] = field(
        default_factory=list,
        metadata={
            "type": "Element",
        }
    )


@dataclass
class Catalog:
    class Meta:
        name = "catalog"

    books: Optional[Books] = field(
        default=None,
        metadata={
            "type": "Element",
        }
    )


@dataclass
class Models:
    class Meta:
        name = "models"

    catalog: Optional[Catalog] = field(
        default=None,
        metadata={
            "type": "Element",
        }
    )

model_con.py

import logging
import sys
import json
from xsdata.formats.dataclass.context import XmlContext
from xsdata.formats.dataclass.parsers import JsonParser
from xsdata.formats.dataclass.parsers.config import ParserConfig
from models.models import Models

from xml_to_json import XmlToJson


class Utilities:
    @staticmethod
    def json_to_model(metadata_json: str) -> Models:
        logger = logging.getLogger(__name__)
        logger.info('%s: Converting JSON to model', sys._getframe().f_code.co_name)
        context: XmlContext = XmlContext()
        config = ParserConfig(fail_on_unknown_attributes=False, fail_on_unknown_properties=False)
        parser: JsonParser = JsonParser(context=context, config=config)
        extract_model: Models = parser.from_string(metadata_json, Models)
        return extract_model


if __name__ == "__main__":
    extract_meta_path = r"C:\XSDATA\sample.xml"
    xtj = XmlToJson()
    xtj.xml_file_name = extract_meta_path
    # print(xtj.json_data)
    ut = Utilities()
    md = ut.json_to_model(metadata_json=xtj.json_data)
    print(md)

原因分析

XSDATA的JSON解析器默认严格区分JSON中的数组([])和单个对象({})。Books类中book字段定义为List[Book],当JSON里book是单个对象而非数组时,解析器无法将单个对象匹配到列表类型的字段,因此会忽略该值,保留字段默认的空列表。


解决方案

在Books类的book字段的metadata中添加"occurs": "unbounded"配置,告知XSDATA该字段既支持单个对象,也支持数组,解析时会自动将单个对象转换为包含该对象的列表。修改后的Books类代码如下:

@dataclass
class Books:
    class Meta:
        name = "books"

    book: List[Book] = field(
        default_factory=list,
        metadata={
            "type": "Element",
            "occurs": "unbounded"  # 添加这一行配置
        }
    )

修改后,无论是单个book对象还是多个book组成的数组,都能被正确解析为List[Book]类型,不会出现空列表的情况。

内容的提问来源于stack exchange,提问作者Ayush Singh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 01:42:37