# System.tag.browse on an perspective object prop

**URL:** <https://forum.inductiveautomation.com/t/system-tag-browse-on-an-perspective-object-prop/24772>\
**Category:** Ignition\
**Tags:** ignition80\
**Created:** [May 7, 2019, 10:56pm UTC](https://forum.inductiveautomation.com/t/system-tag-browse-on-an-perspective-object-prop/24772 "2019-05-07T22:56:05Z")\
**Posts on this page:** 11\
**Page:** 1

<div class="post-metadata">

**Author:** ![mitchell-ACS](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/mitchell-acs/32/30062_2.png) [@mitchell-ACS](https://forum.inductiveautomation.com/u/mitchell-ACS)\
**Post date:** [May 7, 2019, 10:56pm UTC](https://forum.inductiveautomation.com/t/system-tag-browse-on-an-perspective-object-prop/24772/1 "2019-05-07T22:56:05Z")

</div>

I am trying to bind a perspective dropdown component value prop to the results of the sys.tag.browse function, I can get a messy batch pretty easily by using a script transformation on a tag path like this:

```auto
value = '[default]Customers/Demo/nampa_ls/Reads'
new_value = system.tag.browse(value, {}).getResults()
return new_value

Returns: 
[
  {
    "fullPath": "[default]Customers/Demo/nampa_ls/Reads/Pump 2",
    "hasChildren": true,
    "name": "Pump 2",
    "tagType": "Folder"
  },
  {
    "fullPath": "[default]Customers/Demo/nampa_ls/Reads/WW_Level",
    "hasChildren": false,
    "dataType": "Float4",
    "name": "WW_Level",
    "tagType": "AtomicTag",
    "attributes": "[]",
    "value": 27.941008
  },
  {
    "fullPath": "[default]Customers/Demo/nampa_ls/Reads/Pump 1",
    "hasChildren": true,
    "name": "Pump 1",
    "tagType": "Folder"
  }
]

```

This will return the one item I have in that folder and the names of the two folders inside of it.  
However, what I need it to do is to do a recursive search inside the additional folders and return those tags as well. At that point, I need to only use the ‘name’ and ‘fullPath’ in my object to be used with the dropdown component.  
Goal return format:

```auto
[
  {
    "fullPath": "[default]Customers/Demo/nampa_ls/Reads/WW_Level",
    "name": "WW_Level",
  },
  {
    "fullPath": "[default]Customers/Demo/nampa_ls/Reads/Pump 1/Running",
    "name": "Running",
  },
  {
    "fullPath": "[default]Customers/Demo/nampa_ls/Reads/Pump 1/Runtime",
    "name": "Runtime",
  },
  {
    "fullPath": "[default]Customers/Demo/nampa_ls/Reads/Pump 1/Start Count",
    "name": "Start Count",
  }
]

```

I appreciate any help!

---

<div class="post-metadata">

**Author:** ![paul-griffith](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/paul-griffith/32/37249_2.png) [@paul-griffith](https://forum.inductiveautomation.com/u/paul-griffith)\
**Post date:** [May 7, 2019, 11:18pm UTC](https://forum.inductiveautomation.com/t/system-tag-browse-on-an-perspective-object-prop/24772/2 "2019-05-07T23:18:15Z")

</div>

```auto
value = '[default]test_folder'
browse_result = system.tag.browse(value, {}).getResults()
return [{'value': result['fullPath'], 'label': result['name']} for result in browse_result]

```

Nest a dictionary literal inside a list comprehension - so you’re looping through every element from `getResults()`, and for each one, construction a dictionary with `value` and `label` members (necessary for Perspective’s dropdown to work properly).

---

<div class="post-metadata">

**Author:** ![mitchell-ACS](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/mitchell-acs/32/30062_2.png) [@mitchell-ACS](https://forum.inductiveautomation.com/u/mitchell-ACS)\
**Post date:** [May 8, 2019, 3:24pm UTC](https://forum.inductiveautomation.com/t/system-tag-browse-on-an-perspective-object-prop/24772/3 "2019-05-08T15:24:19Z")

</div>

Thats exactly the format I need it in!  
is there a way to incorporate a recursive browse into that?  
I tried adding  
`if result['hasChildren'] == True: browseTags(result['fullPath'], filter)`  
But I keep getting errors.

I also tried creating a function to accomplish this, but that only returns the tag at the root and the two folders, it doesn’t do the recursive browse.  
If I do a simple print instead of return, it does show me all the item, but still only returns the root tags.

```auto
def browseTags(path, filter):
    # Call the browse function
	results = system.tag.browse(path, filter).getResults()
    # Loop through every item in the results and print it
	for result in results:
		if result['hasChildren'] == False:
			print result
        # If the item has children, call the function to repeat the process but starting at the child.
		elif result['hasChildren'] == True:
			browseTags(result['fullPath'], filter)
		#return [{'value': result['fullPath'], 'label': result['name']} for result in results]
# Call the function
browse_results = browseTags('[default]Customers/Demo/nampa_ls/Reads', {})
print [{'value': result['fullPath'], 'label': result['name']} for result in browse_result]

```

---

<div class="post-metadata">

**Author:** ![paul-griffith](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/paul-griffith/32/37249_2.png) [@paul-griffith](https://forum.inductiveautomation.com/u/paul-griffith)\
**Post date:** [May 8, 2019, 3:35pm UTC](https://forum.inductiveautomation.com/t/system-tag-browse-on-an-perspective-object-prop/24772/4 "2019-05-08T15:35:27Z")

</div>

Somewhat naive/optimistic implementation - be careful running this anywhere with lots and lots of tags. Basically just recurses the browseTags function as you had it, but adds the results to a continually growing list. The slice with no arguments (`[:]`) is a slightly underhanded Python way to copy a list in place.

```python
def browseTags(path, browsefilter, current=[]):
    # Call the browse function
	results = system.tag.browse(path, browsefilter).getResults()

	# Loop through every item in a _copy_ of the current results (to avoid concurrently modifying the list)
	for result in results[:]:
		# no need for == True - a true value automatically passes the if check
		if result['hasChildren']:
			browseTags(result['fullPath'], browsefilter, current=results)
		else:
			results.append(result)
	else:
		return results

# Call the function
browse_results = browseTags('[default]', {})
print [{'value': result['fullPath'], 'label': result['name']} for result in browse_results]

```

---

<div class="post-metadata">

**Author:** ![mitchell-ACS](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/mitchell-acs/32/30062_2.png) [@mitchell-ACS](https://forum.inductiveautomation.com/u/mitchell-ACS)\
**Post date:** [May 8, 2019, 4:13pm UTC](https://forum.inductiveautomation.com/t/system-tag-browse-on-an-perspective-object-prop/24772/5 "2019-05-08T16:13:52Z")

</div>

> [@paul-griffith](#):
>
> def browseTags(path, browsefilter, current=): # Call the browse function results = system.tag.browse(path, browsefilter).getResults() # Loop through every item in a _copy_ of the current results (to avoid concurrently modifying the list) for result in results[:]: # no need for == True - a true value automatically passes the if check if result['hasChildren']: browseTags(result['fullPath'], browsefilter, current=results) else: results.append(result) else: return results # Call the function browse\_results = browseTags('[default]', {}) print [{'value': result['fullPath'], 'label': result['name']} for result in browse\_results]

That worked! Thanks for your help @paul-griffith

---

<div class="post-metadata">

**Author:** ![mitchell-ACS](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/mitchell-acs/32/30062_2.png) [@mitchell-ACS](https://forum.inductiveautomation.com/u/mitchell-ACS)\
**Post date:** [May 8, 2019, 6:44pm UTC](https://forum.inductiveautomation.com/t/system-tag-browse-on-an-perspective-object-prop/24772/6 "2019-05-08T18:44:20Z")

</div>

It seems I spoke too soon, I used the wrong tag path in testing it.  
It still only brings back the items at the base of the path, and it seems it now duplicates the tag that is not a folder.

```auto
[
{'label': u'Pump 2', 'value': [default]Customers/Demo/nampa_ls/Reads/Pump 2}, 
{'label': u'WW_Level', 'value': [default]Customers/Demo/nampa_ls/Reads/WW_Level}, 
{'label': u'Pump 1', 'value': [default]Customers/Demo/nampa_ls/Reads/Pump 1}, 
{'label': u'WW_Level', 'value': [default]Customers/Demo/nampa_ls/Reads/WW_Level}
]

```

---

<div class="post-metadata">

**Author:** ![mitchell-ACS](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/mitchell-acs/32/30062_2.png) [@mitchell-ACS](https://forum.inductiveautomation.com/u/mitchell-ACS)\
**Post date:** [May 8, 2019, 8:28pm UTC](https://forum.inductiveautomation.com/t/system-tag-browse-on-an-perspective-object-prop/24772/7 "2019-05-08T20:28:28Z")

</div>

I think I got it working with this:

```auto
def browseTags(path, browsefilter, current=[]):
    # Call the browse function
	results = system.tag.browse(path, browsefilter).getResults()
	tagList = []
	# Loop through every item in a _copy_ of the current results (to avoid concurrently modifying the list)
	for result in results[:]:
		# no need for == True - a true value automatically passes the if check
		if result['hasChildren']:
			recursive_results = browseTags(result['fullPath'], browsefilter, current=results)
			for result in recursive_results:
				tagList.append(result)
		else:
			tagList.append(result)
	return tagList

```

---

<div class="post-metadata">

**Author:** ![paul-griffith](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/paul-griffith/32/37249_2.png) [@paul-griffith](https://forum.inductiveautomation.com/u/paul-griffith)\
**Post date:** [May 8, 2019, 8:33pm UTC](https://forum.inductiveautomation.com/t/system-tag-browse-on-an-perspective-object-prop/24772/8 "2019-05-08T20:33:22Z")

</div>

> [@mitchell-ACS](#):
>
> ```auto
> recursive_results = browseTags(result['fullPath'], browsefilter, current=results) 
> for result in recursive_results:
> tagList.append(result)
> 
> ```

Yeah, that's probably what I missed. You could simplify that code a bit:

```auto
tagList.extend(browseTags(result['fullPath'], browsefilter, current=results))

```

---

<div class="post-metadata">

**Author:** ![mitchell-ACS](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/mitchell-acs/32/30062_2.png) [@mitchell-ACS](https://forum.inductiveautomation.com/u/mitchell-ACS)\
**Post date:** [May 8, 2019, 8:33pm UTC](https://forum.inductiveautomation.com/t/system-tag-browse-on-an-perspective-object-prop/24772/9 "2019-05-08T20:33:48Z")

</div>

I think its due to the dictionary being inside a list, but trying to do any sort of manipulation on the label / value pairs is proving to be difficult.  
To make it more human readable, and because browsing recursively adds a lot of duplicate name tags I am trying to use the ‘fullPath’ twice and splitting down the label string to only show the parent folder of the tag like this:

```auto
[
{'label': Pump 1/Running, 'value': [default]Customers/Demo/meridian_ls/Reads/Pump 1/Running}, 
{'label': Pump 1/Fault, 'value': [default]Customers/Demo/meridian_ls/Reads/Pump 1/Fault}, 
{'label': Pump 1/Runtime, 'value': [default]Customers/Demo/meridian_ls/Reads/Pump 1/Runtime}, 
{'label': Pump 1/Ignition_Minute, 'value': [default]Customers/Demo/meridian_ls/Reads/Pump 1/Ignition_Minute}, 
{'label': Pump 1/Ignition_Second, 'value': [default]Customers/Demo/meridian_ls/Reads/Pump 1/Ignition_Second}, 
{'label': Pump 1/Start_Count, 'value': [default]Customers/Demo/meridian_ls/Reads/Pump 1/Start_Count}
]

```

Is there a simple way of doing that?

---

<div class="post-metadata">

**Author:** ![paul-griffith](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/paul-griffith/32/37249_2.png) [@paul-griffith](https://forum.inductiveautomation.com/u/paul-griffith)\
**Post date:** [May 8, 2019, 8:40pm UTC](https://forum.inductiveautomation.com/t/system-tag-browse-on-an-perspective-object-prop/24772/10 "2019-05-08T20:40:26Z")

</div>

One good option to remove duplication - replace the list structure that’s passed between executions with a dictionary - dictionaries are keyed and will automatically replace duplicate values, so if you key the entries off the full name you won’t end up with duplicates.  
It will change the iteration you have to do at the end, though - you’ll need to loop through the dictionary’s items to pull out the tag objects, then put them into the list comprehension.

As for the splitting question:

```auto
fullpath = "[default]Customers/Demo/meridian_ls/Reads/Pump 1/Start_Count"
print "/".join(fullpath.split("/")[-2:])
>>> 'Pump 1/Start_Count'

```

explained:  
`fullpath.split("/")` turns the string into a list of strings, “split” on the `/` character  
`[-2:]` grabs from the _second to last item_ (`-2`) to the end (nothing after the `:`)  
`"/".join()` takes a sequence of strings and puts them together, using `"/"` as the delimiter - it’s an exact inverse operation to `split()`

---

<div class="post-metadata">

**Author:** ![mitchell-ACS](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/mitchell-acs/32/30062_2.png) [@mitchell-ACS](https://forum.inductiveautomation.com/u/mitchell-ACS)\
**Post date:** [May 9, 2019, 2:28am UTC](https://forum.inductiveautomation.com/t/system-tag-browse-on-an-perspective-object-prop/24772/11 "2019-05-09T02:28:11Z")

</div>

I think I have it where it needs to be, thanks for the help @paul-griffith
