Php 如何从KML/XML中提取数据?

Php 如何从KML/XML中提取数据?,php,ruby,xml,nokogiri,hpricot,Php,Ruby,Xml,Nokogiri,Hpricot,我有一些从KML文件转换成XML的数据,我很好奇如何使用PHP或Ruby来获取邻居的名称和坐标等信息。我知道他们周围有这样的标签 <cities> <neighborhood>Gotham</neighborhood> </cities> 高谭 但不幸的是,数据格式为: <SimpleData name="neighborhd">Colgate Center</SimpleData> 高露洁中心 而不是 <

我有一些从KML文件转换成XML的数据,我很好奇如何使用PHP或Ruby来获取邻居的名称和坐标等信息。我知道他们周围有这样的标签

<cities>
  <neighborhood>Gotham</neighborhood>
</cities>

高谭
但不幸的是,数据格式为:

<SimpleData name="neighborhd">Colgate Center</SimpleData>
高露洁中心
而不是

<neighborhd>Colgate Center</neighborhd>
高露洁中心
这是KML的来源:


如何使用PHP或Ruby从这样的东西中提取数据?我安装了一些用于解析XML数据的Ruby gems,但XML只是我很少使用的东西。

您的XML无效,但Nokogiri将尝试修复它

下面是如何检查无效的XML/XHTML/HTML以及如何重写所需的部分

以下是设置:

require 'nokogiri'

doc = Nokogiri.XML(<<EOT)
<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://earth.google.com/kml/2.2" xmlns:atom="http://www.w3.org/2005/Atom">
  <Document>
    <Schema name="Sample_Neighborhoods_Samples" id="Sample_Neighborhoods_Samples">
      <SimpleField type="int" name="nid"/>
      <SimpleField type="string" name="neighborhd"/>
      <SimpleField type="string" name="place"/>
      <SimpleField type="string" name="placecode"/>
      <SimpleField type="string" name="nbr_type"/>
      <SimpleField type="string" name="po_name"/>
      <SimpleField type="string" name="metro"/>
      <SimpleField type="string" name="country"/>
      <SimpleField type="string" name="state"/>
      <SimpleField type="string" name="statefips"/>
      <SimpleField type="string" name="county"/>
      <SimpleField type="string" name="countyfips"/>
      <SimpleField type="string" name="mcd"/>
      <SimpleField type="string" name="mcdfips"/>
      <SimpleField type="string" name="cbsa"/>
      <SimpleField type="string" name="cbsacode"/>
      <SimpleField type="string" name="cbsatype"/>
      <SimpleField type="double" name="cenlat"/>
      <SimpleField type="double" name="cenlon"/>
      <SimpleField type="int" name="color"/>
      <SimpleField type="string" name="ncs_code"/>
      <SimpleField type="string" name="release"/>
    </Schema>
    <Style id="KMLSTYLER_6">
      <LabelStyle>
        <scale>1.0</scale>
      </LabelStyle>
      <LineStyle>
        <colorMode>normal</colorMode>
      </LineStyle>
      <PolyStyle>
        <color>7f4080ff</color>
        <colorMode>random</colorMode>
      </PolyStyle>
    </Style>
    <name>Sample_Neighborhoods_NYC</name>
    <visibility>1</visibility>
    <Folder id="kml_ft_Sample_Neighborhoods_Samples">
      <name>Sample_Neighborhoods_Samples</name>
      <Folder id="kml_ft_Sample_Neighborhoods_Samples_Sample_Neighborhoods_NYC">
        <name>Sample_Neighborhoods_NYC</name>
        <Placemark id="kml_1">
          <name>Colgate Center</name>
          <Snippet> </Snippet>
          <styleUrl>#KMLSTYLER_6</styleUrl>
          <ExtendedData>
            <SchemaData schemaUrl="#Sample_Neighborhoods_Samples">
              <SimpleData name="nid">7086</SimpleData>
              <SimpleData name="neighborhd">Colgate Center</SimpleData>
              <SimpleData name="place">Jersey City</SimpleData>
              <SimpleData name="placecode">36000</SimpleData>
              <SimpleData name="nbr_type">S</SimpleData>
              <SimpleData name="po_name">JERSEY CITY</SimpleData>
              <SimpleData name="metro">New York City, NY</SimpleData>
              <SimpleData name="country">USA</SimpleData>
              <SimpleData name="state">NJ</SimpleData>
              <SimpleData name="statefips">34</SimpleData>
              <SimpleData name="county">Hudson</SimpleData>
              <SimpleData name="countyfips">34017</SimpleData>
              <SimpleData name="mcd">Jersey City</SimpleData>
              <SimpleData name="mcdfips">36000</SimpleData>
              <SimpleData name="cbsa">New York-Northern New Jersey-Long Island, NY-NJ-PA</SimpleData>
              <SimpleData name="cbsacode">35620</SimpleData>
              <SimpleData name="cbsatype">Metro</SimpleData>
              <SimpleData name="cenlat">40.7145135000001</SimpleData>
              <SimpleData name="cenlon">-74.0343385</SimpleData>
              <SimpleData name="color">1</SimpleData>
              <SimpleData name="ncs_code">40910000</SimpleData>
              <SimpleData name="release">1.12.2</SimpleData>
            </SchemaData>
          </ExtendedData>
          <Polygon>
            <outerBoundaryIs>
              <LinearRing>
                <coordinates>-74.036628,40.712211,0 -74.0357779999999,40.7120810000001,0                     -74.035535,40.7122010000001,0 -74.0348299999999,40.71209,0 -74.034903,40.711804,0 -74.033761,40.7116560000001,0 -74.0334089999999,40.7121090000001,0 -74.032996,40.7141330000001,0 -74.0331899999999,40.7141790000001,0 -74.032656,40.7162500000001,0 -74.032231,40.716194,0 -74.032049,40.716908,0 -74.033871,40.7170370000001,0 -74.035629,40.7173710000001,0 -74.035669,40.7171650000001,0 -74.036009,40.715335,0 -74.036325,40.713625,0 -74.036482,40.7123580000001,0 -74.036628,40.712211,0 </coordinates>
              </LinearRing>
            </outerBoundaryIs>
          </Polygon>
        </Placemark>
        <Placemark id="kml_2">
          <name>Colgate Center</name>
          <Snippet> </Snippet>
          <ExtendedData>
EOT
下面是一种在整个文档中查找
SimpleData
节点的方法。出于可读性原因,我更喜欢使用CSS访问器而不是XPath。有时XPath更好,因为它在搜索时允许更好的粒度。你需要同时学习它们

doc.search('ExtendedData SimpleData').each do |simple_data|
  node_name = simple_data['name']
  puts "<%s>%s</%s>" % [node_name, simple_data.text.strip, node_name]
end
doc.search('extendeddatasimpledata')。每个都做简单的数据|
节点名称=简单数据['name']
放置“%s”%[节点名称,简单数据.text.strip,节点名称]
结束
以下是运行后的输出:

Premature end of data in tag ExtendedData line 87
Premature end of data in tag Placemark line 84
Premature end of data in tag Folder line 44
Premature end of data in tag Folder line 42
Premature end of data in tag Document line 3
Premature end of data in tag kml line 2
<nid>7086</nid>
<neighborhd>Colgate Center</neighborhd>
<place>Jersey City</place>
<placecode>36000</placecode>
<nbr_type>S</nbr_type>
<po_name>JERSEY CITY</po_name>
<metro>New York City, NY</metro>
<country>USA</country>
<state>NJ</state>
<statefips>34</statefips>
<county>Hudson</county>
<countyfips>34017</countyfips>
<mcd>Jersey City</mcd>
<mcdfips>36000</mcdfips>
<cbsa>New York-Northern New Jersey-Long Island, NY-NJ-PA</cbsa>
<cbsacode>35620</cbsacode>
<cbsatype>Metro</cbsatype>
<cenlat>40.7145135000001</cenlat>
<cenlon>-74.0343385</cenlon>
<color>1</color>
<ncs_code>40910000</ncs_code>
<release>1.12.2</release>
标记扩展数据行87中的数据过早结束
标记位置标记行84中的数据过早结束
标记文件夹第44行中的数据过早结束
标记文件夹行42中的数据过早结束
标记文档第3行中的数据过早结束
标记kml第2行中的数据过早结束
7086
高露洁中心
泽西市
36000
s
泽西市
纽约市
美国
新泽西州
34
哈德逊
34017
泽西市
36000
纽约州新泽西州北部长岛,NY-NJ-PA
35620
地铁
40.7145135000001
-74.0343385
1.
40910000
1.12.2
我不想修改DOM,但很容易做到:

doc.search('ExtendedData SimpleData').each do |simple_data|
  node_name = simple_data['name']
  simple_data.replace("<%s>%s</%s>" % [node_name, simple_data.text.strip, node_name])
end

puts doc.to_xml
doc.search('extendeddatasimpledata')。每个都做简单的数据|
节点名称=简单数据['name']
简单\u数据。替换(“%s”%[节点\u名称,简单\u数据.text.strip,节点\u名称])
结束
将doc.xml转换为xml
运行后,这是受影响的部分:

<ExtendedData>
  <SchemaData schemaUrl="#Sample_Neighborhoods_Samples">
    <nid>7086</nid>
    <neighborhd>Colgate Center</neighborhd>
    <place>Jersey City</place>
    <placecode>36000</placecode>
    <nbr_type>S</nbr_type>
    <po_name>JERSEY CITY</po_name>
    <metro>New York City, NY</metro>
    <country>USA</country>
    <state>NJ</state>
    <statefips>34</statefips>
    <county>Hudson</county>
    <countyfips>34017</countyfips>
    <mcd>Jersey City</mcd>
    <mcdfips>36000</mcdfips>
    <cbsa>New York-Northern New Jersey-Long Island, NY-NJ-PA</cbsa>
    <cbsacode>35620</cbsacode>
    <cbsatype>Metro</cbsatype>
    <cenlat>40.7145135000001</cenlat>
    <cenlon>-74.0343385</cenlon>
    <color>1</color>
    <ncs_code>40910000</ncs_code>
    <release>1.12.2</release>
  </SchemaData>
</ExtendedData>

7086
高露洁中心
泽西市
36000
s
泽西市
纽约市
美国
新泽西州
34
哈德逊
34017
泽西市
36000
纽约州新泽西州北部长岛,NY-NJ-PA
35620
地铁
40.7145135000001
-74.0343385
1.
40910000
1.12.2

您的示例KML不正确。请编辑您的问题,并将其替换为实际关闭标签的问题。Nokogiri在解析后返回
errors
中的条目,并且必须通过添加
来修复您的XML。太棒了,我让一切都正常工作了,我只是好奇,一旦我将它放入一个循环中,我可以将计数器放在哪里,这样它就可以完成进程并返回XML中的所有条目,到目前为止我只能返回列表中的第一个什么计数器?它将在
ExtendedData
标记中找到所有
SimpleData
标记。如果您有多个
ExtendedData
标记,它也会处理这些块。我的意思是在我修复它之后。我现在正在解析它,但这样做我只得到第一个邻居返回。此外,它还删除了原始代码中的坐标。(doc/'start')。每个do | st | nh=(st/'neightrhd')。内部html metro=(st/'state')。内部html放置“#{nh}”放置“#{metro}”endI无法告诉您的原始代码是什么,因为您没有让我们看到它。在问题中添加它的摘要版本,或者提供输出内容的准确示例。而且,你只会得到一个邻居,因为你的样本只显示了一个。显示代码和更全面的KML示例,我可以提供更多帮助。事实上,我是瞎了眼,因为你没有给我任何其他的工作。对不起,我刚刚意识到这一点。由于我已经克服了第一个障碍,我可能会尝试自己重新研究并解决它,或者将它作为另一个问题发布,因为它开始与原始问题不同。但是谢谢你,你帮了我很多忙。
<ExtendedData>
  <SchemaData schemaUrl="#Sample_Neighborhoods_Samples">
    <nid>7086</nid>
    <neighborhd>Colgate Center</neighborhd>
    <place>Jersey City</place>
    <placecode>36000</placecode>
    <nbr_type>S</nbr_type>
    <po_name>JERSEY CITY</po_name>
    <metro>New York City, NY</metro>
    <country>USA</country>
    <state>NJ</state>
    <statefips>34</statefips>
    <county>Hudson</county>
    <countyfips>34017</countyfips>
    <mcd>Jersey City</mcd>
    <mcdfips>36000</mcdfips>
    <cbsa>New York-Northern New Jersey-Long Island, NY-NJ-PA</cbsa>
    <cbsacode>35620</cbsacode>
    <cbsatype>Metro</cbsatype>
    <cenlat>40.7145135000001</cenlat>
    <cenlon>-74.0343385</cenlon>
    <color>1</color>
    <ncs_code>40910000</ncs_code>
    <release>1.12.2</release>
  </SchemaData>
</ExtendedData>