Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Plist XPath query with dict elements

I am trying to load song names from an iTunes library export of a plist via Nokigiri:

doc = Nokogiri::XML(open(file.path))

@songs = Array.new  
doc.xpath(<XPATH_HERE>).each do |n|
  @songs.push(n)  #append data to array
end 

The beginning of the plist looks like:

<plist version="1.0">
<dict>
  <key>Major Version</key><integer>1</integer>
  <key>Minor Version</key><integer>1</integer>
  <key>Date</key><date>2014-10-15T22:52:19Z</date>
  <key>Application Version</key><string>11.4</string>
  <key>Features</key><integer>5</integer>
  <key>Show Content Ratings</key><true/>
  <key>Music Folder</key><string>file://localhost/Users/mike/Music/iTunes/iTunes%20Media/</string>
  <key>Library Persistent ID</key><string>280B84572DDCF406</string>
  <key>Tracks</key>
  <dict>
    <key>96</key>
    <dict>
      <key>Track ID</key><integer>96</integer>
      <key>Name</key><string>Get Lucky (Daft Punk cover)</string>
      <key>Artist</key><string>Daughter</string>
      <key>Kind</key><string>MPEG audio file</string>
      <key>Size</key><integer>4716638</integer>
      <key>Total Time</key><integer>294112</integer>
      <key>Date Modified</key><date>2013-11-12T20:54:14Z</date>
      <key>Date Added</key><date>2013-12-18T17:56:09Z</date>
      <key>Bit Rate</key><integer>128</integer>
      <key>Sample Rate</key><integer>44100</integer>
      <key>Persistent ID</key><string>C3B1B6F26134C9C1</string>
      <key>Track Type</key><string>File</string>
      <key>Location</key><string>file://localhost/Users/mike/Music/iTunes/iTunes%20Media/Music/Daughter/Unknown%20Album/Get%20Lucky%20(Daft%20Punk%20cover).mp3</string>
      <key>File Folder Count</key><integer>5</integer>
      <key>Library Folder Count</key><integer>1</integer>
    </dict>
    <key>98</key>
    <dict>
      <key>Track ID</key><integer>98</integer>
      <key>Name</key><string>Swimming in Solace (DJ Fergie Ferg Remash)</string>
      <key>Kind</key><string>MPEG audio file</string>

What I am looking to load from each track is the track name string that comes after the name key. The XPath that I thought should work is

/plist/dict[key[. = 'Tracks']/following-sibling::*[1]]/dict[key/following-sibling::*[1]]/dict[key[. = 'Name']/following-sibling::*[1]]/string

That XPath returns:

<string>Get Lucky (Daft Punk cover)</string>
<string>Daughter</string>
<string>MPEG audio file</string>
<string>C3B1B6F26134C9C1</string>
<string>File</string>
<string>file://localhost/Users/mike/Music/iTunes/iTunes%20Media/Music/Daughter/Unknown%20Album/Get%20Lucky%20(Daft%20Punk%20cover).mp3</string>
<string>Swimming in Solace (DJ Fergie Ferg Remash)</string>
<string>MPEG audio file</string>

It seems that, although my XPath is specifying the key for each string, it is in fact taking the 'following-siblings' of all of each dict regardless.

What can I do to make the query more specific so that this portion of the plist would return:

Get Lucky (Daft Punk cover)

and

Swimming in Solace (DJ Fergie Ferg Remash)
like image 423
muzicmike Avatar asked Oct 17 '14 07:10

muzicmike


People also ask

How do I explicitly select the n-th <item> child element in XPath?

The root element <inventory> has three <item> children, and an <other> child. By using an index [N] on a node in an XPath query, we can explicitly select the N-th <item> child element (counting starts at 1, not 0):

How to query attributes of an XPath?

To query attributes, you can refer to them as a "child" of the element of which they are an attribute. To distinguish attribute names from element names, they must be prefixed with a @character. An @attribute node may only appear as the very last node in an XPath.

How to find the XPath of a field in a form?

Now in all the forms find the table with id ‘tbl_testdm’. Within the table go to a specific row and column. Within the cell, if there are multiple inputs, then find an input where value = ‘Open RFS’, and this will give us the final XPath of the field. Assume that your intended web element lies in the Panel Table and has some common text.

How to check if an XPath is valid or not?

Copy your XPath. Search it in the Browser (F12 or developer tool window) in the DOM to verify if it is valid or not (See the below image). Pro Tip 1: Make sure it is unique and no other web element appears when you search twice in the DOM.


1 Answers

This is one possible XPath :

/plist/dict[key='Tracks']/dict/dict/key[.='Name']/following-sibling::string[1]

The beginning of the XPath may varies, but I think the most important part is the last 2 path steps (key[.='Name']/following-sibling::string[1]). It tell to get the closest <string> element after every <key>Name</key> element.

like image 59
har07 Avatar answered Oct 20 '22 00:10

har07