【问题标题】:Wrong encoded symbols inside XMLXML 中的错误编码符号
【发布时间】:2017-09-08 08:02:40
【问题描述】:

我正在尝试通过“请求”库使用 python 3.4 从某些 Web 服务中获取数据。我需要获取一个有效的 xml 字符串来使用“lxml”库进行解析。但由于某种原因,xml 中的数据编码不正确:

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <soap:Body>
         <xmlData>
         &lt;?xml version="1.0" encoding="UTF-8"?&gt;&lt;Response&gt;&lt;Data&    gt;&lt;Company&gt;... etc.
         </xmlData>
    </soap:Body>
</soap:Envelope>

使用以下代码:

ssession = requests.Session()
session.get(target_url)
exml = session.post(target_url, data=__xml, headers=headers)
print(exml.text)

如何在 XML 中提取没有像“>”这样的符号的数据?如果不手动将&amp;gt; 符号替换为等效符号,这是否可行?

【问题讨论】:

    标签: python xml soap lxml


    【解决方案1】:

    目前您的 SOAP 响应是有效的、格式良好的 XML。字符实体的原因是因为您有一个嵌入式 XML 文档,因此无法为该内部 XML 显示实际标记,以使整个响应保持有效。

    只需解析出嵌入的 XML,将其编码为字节对象以接受特殊的声明字符,然后在其自己的 XML 树中进行解析。

    from io import BytesIO
    import lxml.etree as ET
    
    # same SOAP response code...
    
    # ORIGINAL TREE
    soap_doc = ET.parse(BytesIO(exml.text.encode('utf-8')))
    embedded_data = soap_doc.findall(".//xmlData")[0].text.strip().encode('utf-8')
    
    # NEW TREE
    tree = ET.parse(BytesIO(embedded_data))
    
    # OUTPUT TO FILE
    with open('output.xml', 'wb') as f:
        f.write(ET.tostring(tree, xml_declaration=True, 
                            pretty_print=True, encoding='utf-8'))
    
    #<?xml version='1.0' encoding='utf-8'?>
    #<Response>
    #  <Data>
    #    <Company> </Company>
    #  </Data>
    #</Response>
    

    在此字符串上测试的上述代码完成了有效的&lt;xmlData&gt;,因为 OP 省略了嵌入 XML 的其余部分:

    '''<?xml version="1.0" encoding="utf-8"?>
    <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
        <soap:Body>
             <xmlData>
              &lt;?xml version="1.0" encoding="UTF-8"?&gt;&lt;Response&gt;&lt;Data&gt;&lt;Company&gt; &lt;/Company&gt;&lt;/Data&gt;&lt;/Response&gt;
             </xmlData>
        </soap:Body>
    </soap:Envelope>
    '''
    

    【讨论】:

      【解决方案2】:

      可能还有另一种方法可以做到这一点,但粗粒度的方法是创建一个要转换的字符表并替换它们;

      replacements = {
          "&gt;" : ">",
          "&lt;" : "<"
          }
      
      def replace(xml):
          repl_str = xml
          for char in replacements:
              repl_str = repl_str.replace(char, replacements[char])
          return repl_str
      

      添加注释;一张小桌子可以在这里找到w3schools entities

      【讨论】:

      • 这不会产生符合 W3C 标准的有效 XML,因为在文档中重复打开声明:&lt;?xml ... ?&gt;,从而呈现出格式不正确的 XML。请记住 XML 不是一个简单的文本文件,而是维护标记规则。
      【解决方案3】:

      您可以使用标准库的sax 包中的unescape 函数。

      >>> from xml.sax.saxutils import unescape
      >>> escaped = """&lt;?xml version="1.0" encoding="UTF-8"?&gt;&lt;Response&gt;&lt;Data&gt;&lt;Company&gt;"""
      >>> unescape(escaped)
      '<?xml version="1.0" encoding="UTF-8"?><Response><Data><Company>'
      

      unescape 默认处理 & 和尖括号;您可以传递字典来处理其他替换。来自docs

      xml.sax.saxutils.unescape(数据,实体={})

      在数据字符串中取消转义“&”、“”。

      您可以通过将字典作为可选实体参数传递来取消转义其他数据字符串。键和值都必须是 字符串;每个键都将替换为其对应的值。 '&amp'、'' 始终未转义,即使实体是 提供。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多