fork download
  1. import json
  2. import re
  3.  
  4.  
  5. def pathSegmentParse(path):
  6. '''
  7. Parses a ppath string into logical segments that
  8. can be applied individually.
  9. There are 2 kinds of segments, paths and filters.
  10. Paths indicate a path through the structure.
  11. Filters evaluate an array of substructures to only
  12. those that match
  13. '''
  14. segments = []
  15. parts = re.split('\[|\]',path)
  16. for part in parts:
  17. if not part:
  18. continue
  19. seg = {}
  20. if part[0]=='.':
  21. part = part[1:]
  22. if '=' in part:
  23. sub_parts = part.split('=')
  24. seg['path'] = sub_parts[0]
  25. seg['type'] = 'filter'
  26. seg['value'] = part.split('=')[1]
  27. else:
  28. seg['type'] = 'path'
  29. seg['path'] = part
  30. segments.append(seg)
  31. return segments
  32.  
  33. def applyPath(segment,pointers):
  34. '''
  35. Takes an array of pointers and a ppath segment and returns
  36. a new array of pointers that match the given path
  37. '''
  38. path = segment['path']
  39. parts = path.split('.')
  40. for part in parts:
  41. new_pointers = []
  42. for i in range(0,len(pointers)):
  43. if isinstance(pointers[i], (dict,list)): #then we're not at a simple value
  44. if pointers[i].get(part):
  45. if isinstance(pointers[i][part], list):
  46. for p in pointers[i][part]:
  47. new_pointers.append(p)
  48. else:
  49. new_pointers.append(pointers[i][part])
  50. pointers = new_pointers
  51. return pointers
  52.  
  53. def applyFilter(segment,pointers):
  54. '''
  55. Takes a filter segment of a ppath and applied it
  56. to each pointer and returns an array of pointers
  57. that resolve to the value given in the segment
  58. '''
  59. new_pointers = []
  60. for p in pointers:
  61. value = applyPath(segment,[p])
  62. if value:
  63. if segment['value'] in value:
  64. new_pointers.append(p)
  65. return new_pointers
  66.  
  67.  
  68. def getFromPPath(data,path,default=[]):
  69. '''
  70. Takes a python dict and a ppath string and finds the
  71. matching data in the dict. If no data can be found the
  72. default is returned
  73. '''
  74. pointers = [data]
  75. segments = pathSegmentParse(path)
  76. for segment in segments:
  77. if segment['type'] == 'path':
  78. pointers = applyPath(segment,pointers)
  79. if segment['type'] == 'filter':
  80. pointers = applyFilter(segment,pointers)
  81. if len(pointers)==0:
  82. return default
  83. return pointers
  84.  
  85.  
  86.  
  87. JSON = '''
  88. {
  89. "friends" : [
  90. {"first_name": "Wendell", "last_name": "Jordan", "phone":[{"type":"mobile","number":"440-123-8126"},{"type":"home","number":"440-890-5573"}],"gender":"male"},
  91. {"first_name": "Jeanne", "last_name": "Morris", "phone":[{"type":"mobile","number":"216-123-0079"},{"type":"home","number":"216-890-7830"}],"gender":"female"},
  92. {"first_name": "Herman", "last_name": "Mcdaniel", "phone":[{"type":"mobile","number":"440-123-1344"},{"type":"home","number":"440-890-8825"}],"gender":"male"},
  93. {"first_name": "Emanuel", "last_name": "Becker", "phone":[{"type":"mobile","number":"216-123-8825"},{"type":"home","number":"216-890-8332"}],"gender":"female"},
  94. {"first_name": "Sara", "last_name": "Todd", "phone":[{"type":"mobile","number":"216-123-6117"},{"type":"home","number":"216-890-2899"}],"gender":"female"},
  95. {"first_name": "Victoria", "last_name": "Gray", "phone":[{"type":"mobile","number":"216-123-8456"},{"type":"home","number":"216-890-4469"}],"gender":"female"},
  96. {"first_name": "Ronnie", "last_name": "Cook", "phone":[{"type":"mobile","number":"216-123-2006"},{"type":"home","number":"216-890-2006"}],"gender":"female"},
  97. {"first_name": "Gilbert", "last_name": "Morton", "phone":[{"type":"mobile","number":"440-123-4567"},{"type":"home","number":"440-890-4567"}],"gender":"male"},
  98. {"first_name": "Claudia", "last_name": "Padilla", "phone":[{"type":"mobile","number":"216-123-4567"},{"type":"home","number":"216-890-4567"}],"gender":"female"},
  99. {"first_name": "Doris", "last_name": "Maxwell", "phone":[{"type":"mobile","number":"216-123-4567"},{"type":"home","number":"216-890-4567"}],"gender":"female"},
  100. {"first_name": "Luis", "last_name": "Stokes", "phone":[{"type":"mobile","number":"440-123-4567"},{"type":"home","number":"440-890-4567"}],"gender":"male"},
  101. {"first_name": "Byron", "last_name": "Kelley", "phone":[{"type":"mobile","number":"440-123-4567"},{"type":"home","number":"440-890-4567"}],"gender":"male"},
  102. {"first_name": "Terri", "last_name": "Hayes", "phone":[{"type":"mobile","number":"216-123-4567"},{"type":"home","number":"216-890-4567"}],"gender":"female"},
  103. {"first_name": "Flora", "last_name": "Greene", "phone":[{"type":"mobile","number":"216-123-4567"},{"type":"home","number":"216-890-4567"}],"gender":"female"},
  104. {"first_name": "Guadalupe", "last_name": "Strickland","phone":[{"type":"mobile","number":"216-123-4567"},{"type":"home","number":"216-890-4567"}],"gender":"female"},
  105. {"first_name": "Sylvia", "last_name": "Sutton", "phone":[{"type":"mobile","number":"216-123-4567"},{"type":"home","number":"216-890-4567"}],"gender":"female"},
  106. {"first_name": "Caroline", "last_name": "Perkins", "phone":[{"type":"mobile","number":"216-123-4567"},{"type":"home","number":"216-890-4567"}],"gender":"female"},
  107. {"first_name": "Sherri", "last_name": "Ross", "phone":[{"type":"mobile","number":"216-123-4567"},{"type":"home","number":"216-890-4567"}],"gender":"female"},
  108. {"first_name": "Lloyd", "last_name": "Townsend", "phone":[{"type":"mobile","number":"440-123-4567"},{"type":"home","number":"440-890-4567"}],"gender":"male"},
  109. {"first_name": "Cody", "last_name": "Erickson", "phone":[{"type":"mobile","number":"440-123-4567"},{"type":"home","number":"440-890-4567"}],"gender":"male"},
  110. {"first_name": "Ron", "last_name": "Williams", "phone":[{"type":"mobile","number":"440-123-4567"},{"type":"home","number":"440-890-4567"}],"gender":"male"},
  111. {"first_name": "Francis", "last_name": "Fitzgerald","phone":[{"type":"mobile","number":"216-123-4567"},{"type":"home","number":"216-890-4567"}],"gender":"female"},
  112. {"first_name": "Kenneth", "last_name": "Hopkins", "phone":[{"type":"mobile","number":"440-123-4567"},{"type":"home","number":"440-890-4567"}],"gender":"male"},
  113. {"first_name": "Mary", "last_name": "Ballard", "phone":[{"type":"mobile","number":"216-123-4567"},{"type":"home","number":"216-890-4567"}],"gender":"female"},
  114. {"first_name": "Andre", "last_name": "Lewis", "phone":[{"type":"mobile","number":"440-123-4567"},{"type":"home","number":"440-890-4567"}],"gender":"male"},
  115. {"first_name": "Marguerite", "last_name": "Medina", "phone":[{"type":"mobile","number":"216-123-4567"},{"type":"home","number":"216-890-4567"}],"gender":"female"},
  116. {"first_name": "Rachael", "last_name": "Brown", "phone":[{"type":"mobile","number":"216-123-4567"},{"type":"home","number":"216-890-4567"}],"gender":"female"},
  117. {"first_name": "Daryl", "last_name": "Mccarthy", "phone":[{"type":"mobile","number":"440-123-4567"},{"type":"home","number":"440-890-4567"}],"gender":"male"},
  118. {"first_name": "Shelia", "last_name": "Schultz", "phone":[{"type":"mobile","number":"216-123-4567"},{"type":"home","number":"216-890-4567"}],"gender":"female"},
  119. {"first_name": "Geoffrey", "last_name": "Mcdonald", "phone":[{"type":"mobile","number":"440-123-4567"},{"type":"home","number":"440-890-4567"}],"gender":"male"},
  120. {"first_name": "Tyler", "last_name": "Nichols", "phone":[{"type":"mobile","number":"440-123-4567"},{"type":"home","number":"440-890-4567"}],"gender":"male"},
  121. {"first_name": "Gretchen", "last_name": "Graves", "phone":[{"type":"mobile","number":"216-123-4567"},{"type":"home","number":"216-890-4567"}],"gender":"female"},
  122. {"first_name": "Lora", "last_name": "Pearson", "phone":[{"type":"mobile","number":"216-123-4567"},{"type":"home","number":"216-890-4567"}],"gender":"female"},
  123. {"first_name": "Katie", "last_name": "Watts", "phone":[{"type":"mobile","number":"216-123-4567"},{"type":"home","number":"216-890-4567"}],"gender":"female"},
  124. {"first_name": "Taylor", "last_name": "Jennings", "phone":[{"type":"mobile","number":"216-123-4567"},{"type":"home","number":"216-890-4567"}],"gender":"female"},
  125. {"first_name": "Pamela", "last_name": "Buchanan", "phone":[{"type":"mobile","number":"216-123-4567"},{"type":"home","number":"216-890-4567"}],"gender":"female"},
  126. {"first_name": "Mark", "last_name": "Potter", "phone":[{"type":"mobile","number":"440-123-4567"},{"type":"home","number":"440-890-4567"}],"gender":"male"},
  127. {"first_name": "Domingo", "last_name": "Allen", "phone":[{"type":"mobile","number":"440-123-4567"},{"type":"home","number":"440-890-4567"}],"gender":"male"},
  128. {"first_name": "Jean", "last_name": "Kim", "phone":[{"type":"mobile","number":"216-123-4567"},{"type":"home","number":"216-890-4567"}],"gender":"female"},
  129. {"first_name": "Monique", "last_name": "Sullivan", "phone":[{"type":"mobile","number":"216-123-4567"},{"type":"home","number":"216-890-4567"}],"gender":"female"},
  130. {"first_name": "Theresa", "last_name": "Beck", "phone":[{"type":"mobile","number":"216-123-4567"},{"type":"home","number":"216-890-4567"}],"gender":"female"},
  131. {"first_name": "Morris", "last_name": "Moreno", "phone":[ {"type":"home","number":"440-890-4567"}],"gender":"male"},
  132. {"first_name": "Wade", "last_name": "Luna", "phone":[{"type":"mobile","number":"440-123-4567"},{"type":"home","number":"440-890-4567"}],"gender":"male"},
  133. {"first_name": "Traci", "last_name": "Garcia", "phone":[{"type":"mobile","number":"216-123-4567"},{"type":"home","number":"216-890-4567"}],"gender":"female"},
  134. {"first_name": "Alan", "last_name": "Washington","phone":[{"type":"mobile","number":"440-123-4567"},{"type":"home","number":"440-890-4567"}],"gender":"male"},
  135. {"first_name": "Toni", "last_name": "Weaver", "phone":[{"type":"mobile","number":"216-123-4567"},{"type":"home","number":"216-890-4567"}],"gender":"female"},
  136. {"first_name": "David", "last_name": "Brown", "phone":[{"type":"mobile","number":"440-123-4567"},{"type":"home","number":"440-890-4567"}],"gender":"male"},
  137. {"first_name": "Sergio", "last_name": "Marsh", "phone":[{"type":"mobile","number":"440-123-4567"},{"type":"home","number":"440-890-4567"}],"gender":"male"},
  138. {"first_name": "Charlie", "last_name": "Rice", "phone":[{"type":"mobile","number":"440-123-4567"},{"type":"home","number":"440-890-4567"}],"gender":"male"},
  139. {"first_name": "Bernard", "last_name": "Hogan", "phone":[{"type":"mobile","number":"440-123-4567"},{"type":"home","number":"440-890-4567"}],"gender":"male"}
  140. ]
  141. }
  142. '''
  143.  
  144. data = json.loads(JSON)
  145.  
  146. # how many friends do I have?
  147. assert(len(getFromPPath(data,'friends'))==50)
  148. # how many friends with the last name brown?
  149. assert(len(getFromPPath(data,'friends[last_name=Brown]'))==2)
  150. # What are the first names of the friends whose last names are brown?
  151. assert(getFromPPath(data,'friends[last_name=Brown].first_name')[0]=="Rachael")
  152. assert(getFromPPath(data,'friends[last_name=Brown].first_name')[1]=="David")
  153. # what's the first name of the person with this phone number?
  154. assert(len(getFromPPath(data,"friends[phone.number=216-890-7830].first_name"))==1)
  155. assert(getFromPPath(data,"friends[phone.number=216-890-7830].first_name")[0]=="Jeanne")
  156. # what about this phone number?
  157. assert(len(getFromPPath(data,"friends[phone.number=216-123-0079].first_name"))==1)
  158. assert(getFromPPath(data,"friends[phone.number=216-123-0079].first_name")[0]=="Jeanne")
  159. # How many friends are female?
  160. assert(len(getFromPPath(data,"friends[gender=female]"))==28)
  161. # First names of female friends
  162. assert(len(getFromPPath(data,"friends[gender=female].first_name"))==28)
  163. assert(getFromPPath(data,"friends[gender=female].first_name")[0]=="Jeanne")
  164. assert(getFromPPath(data,"friends[gender=female].first_name")[10]=="Sylvia")
  165. assert(getFromPPath(data,"friends[gender=female].first_name")[27]=="Toni")
  166. # Phone numbers of female friends
  167. assert(len(getFromPPath(data,"friends[gender=female].phone.number"))==56)
  168. assert(getFromPPath(data,"friends[gender=female].phone.number")[0]=="216-123-0079")
  169. assert(getFromPPath(data,"friends[gender=female].phone.number")[10]=="216-123-4567")
  170. assert(getFromPPath(data,"friends[gender=female].phone.number")[55]=="216-890-4567")
  171. # Mobile phone numbers of female friends
  172. assert(len(getFromPPath(data,"friends[gender=female].phone[type=mobile].number"))==28)
  173. assert(getFromPPath(data,"friends[gender=female].phone[type=mobile].number")[0]=="216-123-0079")
  174. assert(getFromPPath(data,"friends[gender=female].phone[type=mobile].number")[10]=="216-123-4567")
  175. assert(getFromPPath(data,"friends[gender=female].phone[type=mobile].number")[27]=="216-123-4567")
  176. # Male friends
  177. assert(len(getFromPPath(data,"friends[gender=male]"))==22)
  178. # Male friends with mobile phones
  179. assert(len(getFromPPath(data,"friends[gender=male][phone.type=mobile]"))==21)
  180. # Male friends with home phones
  181. assert(len(getFromPPath(data,"friends[gender=male][phone.type=home]"))==22)
  182. # First names of male friends with home phones
  183. assert(getFromPPath(data,"friends[gender=male][phone.type=home].first_name")[0]=="Wendell")
  184. assert(getFromPPath(data,"friends[gender=male][phone.type=home].first_name")[10]=="Daryl")
  185. assert(getFromPPath(data,"friends[gender=male][phone.type=home].first_name")[21]=="Bernard")
  186. # Male friends with fax numbers
  187. assert(len(getFromPPath(data,"friends[gender=male][phone.type=fax]"))==0)
  188.  
  189.  
  190.  
  191.  
  192.  
Success #stdin #stdout 0.03s 9192KB
stdin
Standard input is empty
stdout
Standard output is empty