如何在Django REST中从HTTP XML请求获取标签属性?
解决Django REST Framework XML解析器无法提取标签属性的问题
结论:无法通过HTTP请求头保留XML标签属性
HTTP请求头仅用于传递请求元信息(如Content-Type),无法改变djangorestframework-xml默认解析器的逻辑——它默认只提取XML元素的层级结构和文本内容,会直接忽略标签属性。必须通过自定义XML解析器来实现属性提取。
解决方案1:基于xmltodict实现自定义解析器
xmltodict库可以直接将XML转换为包含属性的字典结构,步骤如下:
- 安装依赖:
pip install xmltodict
- 定义自定义解析器类:
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
- 在视图中使用该解析器:
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
相关产品推荐
相关产品推荐

