价值“翻倍”在 Nokogiri 中选择 XML

发布于 2024-11-17 09:08:42 字数 2253 浏览 4 评论 0原文

<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。但我不知道解决办法。

<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)

I always get double entries in my result:

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

I want something like this:

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

The problem could be the xmlns. But I don't know a solution.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

不甘平庸 2024-11-24 09:08:42
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"}]
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"}]
沩ん囻菔务 2024-11-24 09:08:42

您的问题出在您的 XPath 选择器上。当您编写时:

i.xpath('//xmlns: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 代替,它返回第一个匹配元素。事实上,除非您的架构不稳定,否则我还会准确指定在哪里找到我想要的 Altitude:

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}]

Your problem is with your XPath selector. When you write:

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

you start at the root of the document and find every <AltitudeMeters> element at any level, not just children of the track that you are currently looking at. The minimum change you can make is to alter your XPath selector to be .//xmlns:AltitudeMeters (note the leading period):

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"}]

Additionally, if there is only one Trackpoint per track, I would use at_xpath instead, which returns the first matching element. Indeed, unless your schema is volatile, I would also specify exactly where to find the Altitude I wanted:

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

Finally, since you seem to be working with a document with a single namespace, note that you can ask Nokogiri to drop all namespaces to make your life simpler:

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}]
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文