我在python

时间:2017-01-06 16:26:34

标签: python xml xpath lxml

我正在尝试使用xpath查询和lxml模块获取不同的值。 所以我的代码似乎工作正常,但我有两个问题,我无法解决。 Xml

<?xml version='1.0' encoding='UTF-8'?>
<osm version="0.6" generator="osmconvert 0.8.5">
        <node id="429459476" lat="55.6091243" lon="37.7270414" version="2" timestamp="2012-02-20T18:13:50Z" changeset="10743203" uid="210173" user="osmmaker">
        <tag k="amenity" v="library"/>
        <tag k="name" v="Детская библиотека №101"/>
        <tag k="opening_hours" v="Mo-Fr 12:00-18:00; Sa 12:00-17:00"/>
        <tag k="phone" v="+7-495-3995297"/>
    </node>
    <node id="448176571" lat="55.6098905" lon="37.7317767" version="2" timestamp="2009-11-03T16:02:27Z" changeset="3025778" uid="75496" user="navigARTor">
        <tag k="highway" v="bus_stop"/>
        <tag k="name" v="Воронежская улица"/>
    </node>
    <node id="448176571" lat="55.6098905" lon="37.7317767" version="2" timestamp="2009-11-03T16:02:27Z" changeset="3025778" uid="75496" user="navigARTor">
        <tag k="highway" v="bus_stop"/>
        <tag k="name" v="Воронежская улица"/>
    </node>
</osm>

Python代码

from lxml import etree
tree = etree.parse('out.xml')
tags = tree.xpath('./node[tag[not(@k = preceding::tag/@k)]]')
with open('10.xml','w') as f:
    for tag in tags:
          f.write(etree.tostring(tag,pretty_print=True).decode())

xpath查询后的Xml

<node id="429459476" lat="55.6091243" lon="37.7270414" version="2" timestamp="2012-02-20T18:13:50Z" changeset="10743203" uid="210173" user="osmmaker">
        <tag k="amenity" v="library"/>
        <tag k="name" v="&#1044;&#1077;&#1090;&#1089;&#1082;&#1072;&#1103; &#1073;&#1080;&#1073;&#1083;&#1080;&#1086;&#1090;&#1077;&#1082;&#1072; &#8470;101"/>
        <tag k="opening_hours" v="Mo-Fr 12:00-18:00; Sa 12:00-17:00"/>
        <tag k="phone" v="+7-495-3995297"/>
    </node>


<node id="448176571" lat="55.6098905" lon="37.7317767" version="2" timestamp="2009-11-03T16:02:27Z" changeset="3025778" uid="75496" user="navigARTor">
        <tag k="highway" v="bus_stop"/>
        <tag k="name" v="&#1042;&#1086;&#1088;&#1086;&#1085;&#1077;&#1078;&#1089;&#1082;&#1072;&#1103; &#1091;&#1083;&#1080;&#1094;&#1072;"/>
    </node>

问题#1

如何获取完整的xml文档,如:

<?xml version='1.0' encoding='UTF-8'?>
<osm version="0.6" generator="osmconvert 0.8.5">
        <node id="429459476" lat="55.6091243" lon="37.7270414" version="2" timestamp="2012-02-20T18:13:50Z" changeset="10743203" uid="210173" user="osmmaker">
        <tag k="amenity" v="library"/>
        <tag k="name" v="&#1044;&#1077;&#1090;&#1089;&#1082;&#1072;&#1103; &#1073;&#1080;&#1073;&#1083;&#1080;&#1086;&#1090;&#1077;&#1082;&#1072; &#8470;101"/>
        <tag k="opening_hours" v="Mo-Fr 12:00-18:00; Sa 12:00-17:00"/>
        <tag k="phone" v="+7-495-3995297"/>
    </node>
<node id="448176571" lat="55.6098905" lon="37.7317767" version="2" timestamp="2009-11-03T16:02:27Z" changeset="3025778" uid="75496" user="navigARTor">
        <tag k="highway" v="bus_stop"/>
        <tag k="name" v="&#1042;&#1086;&#1088;&#1086;&#1085;&#1077;&#1078;&#1089;&#1082;&#1072;&#1103; &#1091;&#1083;&#1080;&#1094;&#1072;"/>
    </node>
</osm>
问题#2 以及如何摆脱这个abracadabra

v="&#1042;&#1086;&#1088;&#1086;&#1085;&#1077;&#1078;&#1089;&#1082;&#1072;&#1103; &#1091;&#1083;&#1080;&#1094;&#1072

P.S。抱歉我的英文不好,希望你能理解

1 个答案:

答案 0 :(得分:2)

考虑使用XPath的兄弟XSLT来操纵源XML。虽然XPath非常适合解析文档的选定区域,但XSLT是一种专用于转换文档的语言。具体而言,您需要的更多是Muenchian Method,您可以通过元素/属性值(使用xsl:key)为文档编制索引,以便进行分组以返回不同的值。我们在这里使用node/@id

Python的lxml模块可以处理XSLT 1.0脚本。由于这些脚本是格式良好的XML文件,因此可以从文件或嵌入字符串中解析它们。这条路线的另一个原因是保留unicode,即原始输出的挑战,因为etree.tostring()方法正在为特殊的西里尔字符呈现character entities

XSLT 脚本(另存为.xsl)

<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
 <xsl:output version="1.0" encoding="UTF-8" indent="yes" />
 <xsl:strip-space elements="*"/>

 <xsl:key name="nodekey" match="node" use="@id" />

  <xsl:template match="/osm">   
   <xsl:copy>
     <xsl:copy-of select="@*"/>
     <xsl:for-each select="node[count(. | key('nodekey', @id))]">
      <xsl:copy>        
        <xsl:copy-of select="@*|*"/>
      </xsl:copy>
    </xsl:for-each>
   </xsl:copy>
  </xsl:template>

</xsl:transform>

Python 脚本

from lxml import etree

xml = etree.parse('Input.xml')
xsl = etree.parse('XSLTScript.xsl')

transform = etree.XSLT(xsl)
newdom = transform(xml)

with open('Output.xml', 'wb') as f:
    f.write(newdom)

XML 输出

<?xml version="1.0" encoding="UTF-8"?>
<osm version="0.6" generator="osmconvert 0.8.5">
  <node id="429459476" lat="55.6091243" lon="37.7270414" version="2" timestamp="2012-02-20T18:13:50Z" changeset="10743203" uid="210173" user="osmmaker">
    <tag k="amenity" v="library"/>
    <tag k="name" v="Детская библиотека №101"/>
    <tag k="opening_hours" v="Mo-Fr 12:00-18:00; Sa 12:00-17:00"/>
    <tag k="phone" v="+7-495-3995297"/>
  </node>
  <node id="448176571" lat="55.6098905" lon="37.7317767" version="2" timestamp="2009-11-03T16:02:27Z" changeset="3025778" uid="75496" user="navigARTor">
    <tag k="highway" v="bus_stop"/>
    <tag k="name" v="Воронежская улица"/>
  </node>
</osm>