0

I am trying to parse information off of a Garmin 500 file. I have successfully read in the data:

data <- xmlInternalTreeParse("C:/Users/Ryan Caldwell/Documents/1_26_2014 11_04_29 AM_history.tcx", useInternalNodes=T) 

But after I use the xpathApply function I am receiving:

 x <- xpathApply(data, "/TrainingCenterDatabase//Calories", xmlValue)
> x
list()

Here is what some of the file looks like:

<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<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/ActivityExtension/v2 http://www.garmin.com/xmlschemas/ActivityExtensionv2.xsd http://www.garmin.com/xmlschemas/FatCalories/v1 http://www.garmin.com/xmlschemas/fatcalorieextensionv1.xsd http://www.garmin.com/xmlschemas/TrainingCenterDatabase/v2 http://www.garmin.com/xmlschemas/TrainingCenterDatabasev2.xsd">

  <Activities>
    <Activity Sport="Biking">
     <Id>2014-01-26T17:04:29Z</Id>
     <Lap StartTime="2014-01-26T17:04:29Z">
       <TotalTimeSeconds>1104.6240000</TotalTimeSeconds>
       <DistanceMeters>8046.7397461</DistanceMeters>
       <MaximumSpeed>12.2260008</MaximumSpeed>
       <Calories>170</Calories>
       <AverageHeartRateBpm xsi:type="HeartRateInBeatsPerMinute_t">
         <Value>122</Value>
       </AverageHeartRateBpm>
       <MaximumHeartRateBpm xsi:type="HeartRateInBeatsPerMinute_t">
         <Value>148</Value>
       </MaximumHeartRateBpm>
       <Intensity>Resting</Intensity>
       <TriggerMethod>Distance</TriggerMethod>

Why is there nothing in the list?

Ryan Caldwell
  • 107
  • 2
  • 13
  • have a look at `data`. You are probably skipping a node, possibly the first one. Try `"/data/TrainingCenterDatabase//Calories"` or `"/doc/TrainingCenterDatabase//Calories"` – Ricardo Saporta Jan 27 '14 at 03:44

2 Answers2

1

There are a couple of problems here.

First, your sample xml file is malformed. Aside from the fact that you left off some of the closing tags, the namespace URIs must be enclosed in quotes, e.g.:

xmlns="http://www.garmin.com/xmlschemas/TrainingCenterDatabase/v2"

and not

xmlns=http://www.garmin.com/xmlschemas/TrainingCenterDatabase/v2

As is, I can't understand how to document could have been loaded in the first place.

Second (once the issues above are fixed), @har07 is basically correct. Since you have a default namespace declared, you have to refer to it in your xPath. Unfortunately, just using ns: doesn't work:

x <- xpathApply(data, "/ns:TrainingCenterDatabase//ns:Calories", xmlValue)
# XPath error : Undefined namespace prefix
# XPath error : Invalid expression
# Error in xpathApply.XMLInternalDocument(data, "/ns:TrainingCenterDatabase//ns:Calories",  : 
#   error evaluating xpath expression /ns:TrainingCenterDatabase//ns:Calories

Instead, you have to declare ns to be the default namespace in the call to xpathApply, as follows:

ns <- c(ns="http://www.garmin.com/xmlschemas/TrainingCenterDatabase/v2")
x  <- xpathApply(data, "/ns:TrainingCenterDatabase//ns:Calories", xmlValue, namespaces=ns)
x
# [[1]]
# [1] "170"

The first line above creates a named vector with one element, ns, containing the URI of the default namespace. Now, using ns:Calories (etc.) will work.

Finally, you can use a simpler xPath string and get the same result:

x <- xpathApply(data, "//ns:Calories", xmlValue, namespaces=ns)
jlhoward
  • 58,004
  • 7
  • 97
  • 140
0

Since sample XML posted has default namespace, I suggest to try supplying namespace prefix to XPath query. Something like this :

x <- xpathApply(data, "/ns:TrainingCenterDatabase//ns:Calories", namespaces = c(ns = "http://www.garmin.com/xmlschemas/TrainingCenterDatabase/v2"))

[Reference]

Not sure if above is the correct syntax, I know nothing about . But the concept is (in my understanding, CMIIW), when prefix is not supplied in XPath query it will be considered as element with no namespace. And in XML, when the file has default namespace declared, all element without prefix will be considered as in default namespace.

UPDATE :

Tiny fix. Based on @jlhoward answer my sample snippet above missing one parameter xmlValue. It should be :

x <- xpathApply(data, "/ns:TrainingCenterDatabase//ns:Calories", xmlValue, namespaces = c(ns = "http://www.garmin.com/xmlschemas/TrainingCenterDatabase/v2"))
Community
  • 1
  • 1
har07
  • 88,338
  • 12
  • 84
  • 137