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

如何在Django REST中从HTTP XML请求获取标签属性?

解决Django REST Framework XML解析器无法提取标签属性的问题

结论:无法通过HTTP请求头保留XML标签属性

HTTP请求头仅用于传递请求元信息(如Content-Type),无法改变djangorestframework-xml默认解析器的逻辑——它默认只提取XML元素的层级结构和文本内容,会直接忽略标签属性。必须通过自定义XML解析器来实现属性提取。

解决方案1:基于xmltodict实现自定义解析器

xmltodict库可以直接将XML转换为包含属性的字典结构,步骤如下:

  1. 安装依赖:
pip install xmltodict
  1. 定义自定义解析器类:
from rest_framework_xml.parsers import XMLParser
import xmltodict

class CustomXMLParser(XMLParser):
    def parse(self, stream, media_type=None, parser_context=None):
        parser_context = parser_context or {}
        encoding = parser_context.get('encoding', self.encoding)
        # 读取并解码XML流
        xml_content = stream.read().decode(encoding)
        # 解析XML,将属性直接作为字典键(去掉默认前缀)
        parsed_data = xmltodict.parse(
            xml_content,
            attr_prefix='',
            dict_constructor=dict,
            process_namespaces=False
        )
        return parsed_data
  1. 在视图中使用该解析器:
from rest_framework.decorators import api_view, parser_classes
from rest_framework.response import Response

@api_view(['GET', 'POST'])
@parser_classes([CustomXMLParser])
def my_view(request):
    if request.method == 'POST':
        return Response({'received_data': request.data})

解析后你的示例XML会得到如下结果:

{
    "received_data": {
        "CEF": {
            "Element": {
                "p": {
                    "x": "1",
                    "y": "2"
                }
            }
        }
    }
}

解决方案2:基于原生etree手动实现属性提取

如果不想引入第三方库,可以基于xml.etree.ElementTree手动遍历XML元素,提取属性和子元素:

from rest_framework_xml.parsers import XMLParser
from xml.etree.ElementTree import fromstring

class AttributeXMLParser(XMLParser):
    def parse(self, stream, media_type=None, parser_context=None):
        parser_context = parser_context or {}
        encoding = parser_context.get('encoding', self.encoding)
        xml_content = stream.read().decode(encoding)
        root_element = fromstring(xml_content)
        return self._traverse_element(root_element)
    
    def _traverse_element(self, element):
        element_data = {}
        # 先提取当前元素的所有属性
        if element.attrib:
            element_data.update(element.attrib)
        # 遍历子元素
        child_elements = list(element)
        if child_elements:
            children_data = {}
            for child in child_elements:
                child_key = child.tag
                child_value = self._traverse_element(child)
                # 处理重复标签,转为列表
                if child_key in children_data:
                    if not isinstance(children_data[child_key], list):
                        children_data[child_key] = [children_data[child_key]]
                    children_data[child_key].append(child_value)
                else:
                    children_data[child_key] = child_value
            element_data.update(children_data)
        # 处理元素的非空文本内容
        elif element.text and element.text.strip():
            element_data = element.text.strip()
        return element_data

替换视图中的解析器后,request.data会包含标签属性,示例XML的解析结果为:

{
    "received_data": {
        "Element": {
            "p": {
                "x": "1",
                "y": "2"
            }
        }
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 07:25:14