【问题标题】:Escaping bad XML while parsing在解析时转义错误的 XML
【发布时间】:2018-10-19 04:14:11
【问题描述】:

我正在尝试从不属于我的 XML 站点地图中解析 URL。不幸的是,有些 XML 写得不好,并且包含未转义/无效的字符,例如 & 符号。

这是我目前用来解析我的 XML 文件的代码块:

from xml.etree import ElementTree as ET

tree = ET.parse('test.xml')
root = tree.getroot()

name_space = '{http://www.sitemaps.org/schemas/sitemap/0.9}'

urls = []
for child in root.iter():
    for block in child.findall('{}url'.format(name_space)):
        for url in block.findall('{}loc'.format(name_space)):
            urls.append('{}\n'.format(url.text))

with open('sample_urls.txt', 'w+') as f:
    f.writelines(urls)

遇到未转义的 URL 时遇到此错误:ParseError: not well-formed (invalid token)。

如何避免这些问题并继续解析文件?我遇到了 xml.sax.saxutils 模块的 escape() 功能,但根据我目前的情况不确定应用它的最佳方式。

【问题讨论】:

  • 我找到了一种解决方法来忽略这些问题,方法是切换到 lxml 工具包下的 etree 并添加 'parser = ET.XMLParser(recover=True)' 和 'tree = ET.parse('test.xml ',解析器=解析器)'。这似乎删除了有问题的 URL 部分并继续。没有逃跑的想法,但可以在紧要关头工作。
  • 您不能预处理 XML 并删除所有无效字符吗?当然,您无法避免例如未关闭的元素,但这应该是一个开始。如果您可以发布一些带有您遇到的错误的 XML sn-ps,那就太好了。
  • 我遇到的问题是弄清楚如何在不弄乱 XML 的有效部分的情况下进行预处理。我只需要转义 url 节点中的内容。这是一个损坏的 XML 站点地图示例:samsclub.com/sitemap_products_1.xml

标签: python xml python-3.x elementtree


【解决方案1】:

如果可以,请尝试使用lxml.html。不过,您应该小心;它会忽略命名空间,因此您需要确保选择的是您打算选择的内容。

示例...

sitemap_products_1.xml(您链接到的那个的缩短版本。注意第二个urlloc 值不好。)

<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
 xmlns:image="http://www.google.com/schemas/sitemap-image/1.1">
 <url>
  <loc>https://www.samsclub.com/sams/mirror-convex/prod13760282.ip</loc>
  <image:image>
   <image:title>See All 160 Degree Convex Security Mirror - 24&quot; w x 15&quot; h</image:title>
   <image:loc>https://scene7.samsclub.com/is/image/samsclub/0003308171524_A</image:loc>
  </image:image>
 </url>
 <url>
  <loc>https://www.samsclub.com/sams/at&t-3-handset-cordless-phone/prod21064454.ip</loc>
  <image:image>
   <image:title>AT&amp;T 3 Handset Cordless Phone</image:title>
   <image:loc>https://scene7.samsclub.com/is/image/samsclub/0065053003067_A</image:loc>
  </image:image>
 </url>
 <url>
  <loc>https://www.samsclub.com/sams/premium-free-flow-waterbed-mattress-kit-queen/104864.ip</loc>
  <image:image>
   <image:title>Premium Free Flow Waterbed Mattress Kit- Queen</image:title>
   <image:loc>https://scene7.samsclub.com/is/image/samsclub/0040649555859_A</image:loc>
  </image:image>
 </url>
</urlset>

Python 3.x

from lxml import html

tree = html.parse("sitemap_products_1.xml")

for elem in tree.findall(".//url/loc"):
    print(elem.text)

输出(注意第二个 url 已完整打印。)

https://www.samsclub.com/sams/mirror-convex/prod13760282.ip
https://www.samsclub.com/sams/at&t-3-handset-cordless-phone/prod21064454.ip
https://www.samsclub.com/sams/premium-free-flow-waterbed-mattress-kit-queen/104864.ip

【讨论】:

  • 有趣,这绝对适合我的目的。
【解决方案2】:

鉴于您发布的示例,我想说,当涉及到 &amp;amp; 字符时,使用正则表达式就足够了。除非您完全想删除此类 &lt;loc/&gt; 元素。下面的“算法”应该可以帮助您恢复此类错误。

  1. 由于.../at&amp;t-3-handset-cordless... 内部的&amp;t- 显然是 不是有效的 & 字符代码,您可以捕获所有内容 在&lt;loc/&gt; 的值内的&amp;amp; 和第一个; 之间或 结束标记的开头(&lt;/,即&lt;/loc&gt;)。

  2. 然后你可以检查捕获的字符串是否确实是一个 & 字符代码(因为这些是有限的,你可以创建一个 设置并检查字符串是否在里面)。如果不是,则更换 那个(只有那个!)与&amp;amp; 字符串。

  3. 从替换 &amp;amp; 的位置继续并继续迭代,直到你覆盖 完整的&lt;loc/&gt; 元素。

之后,您可以运行 XML 解析器,并且由于所有无效的 & 字符代码都已被替换,您应该能够获得格式良好的 XML,除非它有其他问题。

请注意,这只是我的想法。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-09-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-15
    • 2017-03-16
    相关资源
    最近更新 更多