Значения «удвоились» при выборе XML в Nokogiri - PullRequest
2 голосов
/ 26 июня 2011
<TrainingCenterDatabase xmlns="http://www.garmin.com/xmlschemas/TrainingCenterDatabase/v2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.garmin.com/xmlschemas/TrainingCenterDatabase/v2 http://www.garmin.com/xmlschemas/TrainingCenterDatabasev2.xsd">
  <Activities>
    <Activity Sport="Running">
      <Id>2011-04-29T15:29:42Z</Id>
      <Lap StartTime="2011-04-29T15:29:42Z">
        <TriggerMethod>Manual</TriggerMethod>
        <Track>
          <Trackpoint>
            <AltitudeMeters>298.6267090</AltitudeMeters>
            <Position>
              <LatitudeDegrees>52.4864997</LatitudeDegrees>
              <LongitudeDegrees>13.3531452</LongitudeDegrees>
            </Position>
          </Trackpoint>
        </Track>
      </Lap>
      <Lap StartTime="2011-04-29T15:29:42Z">
        <TriggerMethod>Manual</TriggerMethod>
        <Track>
          <Trackpoint>
            <AltitudeMeters>498.6267090</AltitudeMeters>
            <Position>
              <LatitudeDegrees>52.4864997</LatitudeDegrees>
              <LongitudeDegrees>13.3531452</LongitudeDegrees>
            </Position>
          </Trackpoint>
         </Track>
      </Lap>
    </Activity>
  </Activities>
</TrainingCenterDatabase>
doc = Nokogiri::XML(xml)
node_values = doc.xpath('//xmlns:Track', 'xmlns' => 'http://www.garmin.com/xmlschemas/TrainingCenterDatabase/v2').map do |i|     
  {'AltitudeMeters' => i.xpath('//xmlns:AltitudeMeters').text}
end
nl.debug(node_values)

Я всегда получаю двойные записи в моем результате:

[{"AltitudeMeters"=>"298.6267090498.6267090"},
 {"AltitudeMeters"=>"298.6267090498.6267090"}]

Я хочу что-то вроде этого:

[{"AltitudeMeters"=>"298.6267090"},
 {"AltitudeMeters"=>"498.6267090"}]

Проблема может быть в xmlns. Но я не знаю решения.

Ответы [ 2 ]

2 голосов
/ 26 июня 2011
doc = Nokogiri::XML(xml)
node_values = doc.xpath('//xmlns:Track//xmlns:AltitudeMeters', 'xmlns' => 'http://www.garmin.com/xmlschemas/TrainingCenterDatabase/v2').map do |i|     
    {'AltitudeMeters' => i.text}
end
p node_values
# => [{"AltitudeMeters"=>"298.6267090"}, {"AltitudeMeters"=>"498.6267090"}]
1 голос
/ 27 июня 2011

Ваша проблема с вашим селектором XPath. Когда вы пишете:

i.xpath('//xmlns:AltitudeMeters')

вы начинаете с корня документа и находите каждый элемент <AltitudeMeters> на любом уровне, а не только дочерние элементы дорожки, которую вы просматриваете в данный момент. Минимальное изменение, которое вы можете сделать, это изменить ваш селектор XPath на .//xmlns:AltitudeMeters (обратите внимание на начальный период):

doc = Nokogiri::XML(xml)
tracks = doc.xpath( '//xmlns:Track' ) # You don't need to specify the namespace
node_values = tracks.map do |track|
  { 'AltitudeMeters' => track.xpath('.//xmlns:AltitudeMeters').text }
end
p node_values
#=> {"AltitudeMeters"=>"298.6267090"}, {"AltitudeMeters"=>"498.6267090"}]

Кроме того, если на дорожку есть только один Trackpoint, я бы использовал at_xpath, что возвращает первый соответствующий элемент. Действительно, если ваша схема не является изменчивой, я бы также указал, где именно найти высоту, которую я хотел:

node_values = tracks.map do |track|
  { 'AltitudeMeters' =>
    track.at_xpath('./xmlns:Trackpoint/xmlns:AltitudeMeters').text }
end

Наконец, поскольку вы, кажется, работаете с документом с одним пространством имен, обратите внимание, что вы можете попросить Nokogiri отбросить все пространства имен, чтобы сделать вашу жизнь проще:

doc = Nokogiri::XML(xml)
doc.remove_namespaces!
node_values = doc.xpath( '//Track/Trackpoint' ).map do |track|
  {
    'Altitude'  => track.at_xpath('./AltitudeMeters').text.to_f,
    'Latitude'  => track.at_xpath('./Position/LatitudeDegrees').text.to_f,
    'Longitude' => track.at_xpath('./Position/LongitudeDegrees').text.to_f
  }
end

require 'pp'
pp node_values
#=> [{"Altitude"=>298.626709, "Latitude"=>52.4864997, "Longitude"=>13.3531452},
#=>  {"Altitude"=>498.626709, "Latitude"=>52.4864997, "Longitude"=>13.3531452}]
...