This works for me in ArcGIS Online, you need to replace <UserName>, <Password> and <ItemId>. Put it in a PythonCaller and it will return a feature with a list called "layer_names".
import fme
import fmeobjects
from arcgis.gis import GIS
from arcgis.mapping import WebMap
class FeatureProcessor(object):
def __init__(self):
pass
def has_support_for(self, support_type: int):
return support_type == fmeobjects.FME_SUPPORT_FEATURE_TABLE_SHIM
def input(self, feature: fmeobjects.FMEFeature):
# Connect to your ArcGIS Online organization or Portal for ArcGIS
gis = GIS("https://www.arcgis.com", "<UserName>", "<Password>")
# Get the web map item by its ID
web_map_id = "<ItemId>"
web_map_item = gis.content.get(web_map_id)
web_map = WebMap(web_map_item)
# Create an empty list to store layer names
layer_names = []
# Append each layer name to the list
for layer in web_map.layers:
layer_names.append(layer.title)
# Create a feature with the list of layer names
feature_out = fmeobjects.FMEFeature()
feature_out.setAttribute("layer_names", layer_names)
self.pyoutput(feature_out)
def close(self):
pass
def process_group(self):
pass
Hi, I am getting an error
2024-04-08 14:26:28| 11.6| 4.6|ERROR |Python Exception <Exception>: A general error occurred: Could not login. Please ensure you have valid credentials and set your security login question.
2024-04-08 14:26:28| 11.6| 0.0|ERROR |Traceback (most recent call last):
2024-04-08 14:26:28| | |ERROR | File "C:\Program Files\ArcGIS\Pro\bin\Python\envs\arcgispro-py3\lib\site-packages\arcgis\auth\_auth\_token.py", line 841, in token
2024-04-08 14:26:28| | |ERROR | self._init_response_type_token()
2024-04-08 14:26:28| | |ERROR | File "C:\Program Files\ArcGIS\Pro\bin\Python\envs\arcgispro-py3\lib\site-packages\arcgis\auth\_auth\_token.py", line 540, in _init_response_type_token
2024-04-08 14:26:28| | |ERROR | raise Exception("Unable to generate oauth token")
2024-04-08 14:26:28| | |ERROR |Exception: Unable to generate oauth token
I have opened fresh FME 2023.0 workbend and have only Creator and PythonCaller with:
- Esri ArcGIS Python 3.7+
- and following script
import fme
import fmeobjects
from arcgis.gis import GIS
from arcgis.mapping import WebMap
class FeatureProcessor(object):
def __init__(self):
pass
def has_support_for(self, support_type: int):
return support_type == fmeobjects.FME_SUPPORT_FEATURE_TABLE_SHIM
def input(self, feature: fmeobjects.FMEFeature):
# Connect to your ArcGIS Online organization or Portal for ArcGIS
gis = ("https://maps-eu.ramboll.com/portal", "USERNAME", "PASSWORD")
# Get the web map item by its ID
web_map_id = "ITEMID"
web_map_item = gis.content.get(web_map_id)
web_map = WebMap(web_map_item)
# Create an empty list to store layer names
layer_names = []
# Append each layer name to the list
for layer in web_map.layers:
layer_names.append(layer.title)
# Create a feature with the list of layer names
feature_out = fmeobjects.FMEFeature()
feature_out.setAttribute("layer_names", layer_names)
self.pyoutput(feature_out)
def close(self):
pass
def process_group(self):
pass
Now for a change I get following error
2024-04-12 14:23:00| 8.3| 0.0|ERROR |Python Exception <AttributeError>: 'tuple' object has no attribute 'content'2024-04-12 14:23:00| 8.3| 0.0|ERROR |Traceback (most recent call last):2024-04-12 14:23:00| | |ERROR | File "<string>", line 22, in input2024-04-12 14:23:00| | |ERROR |AttributeError: 'tuple' object has no attribute 'content'2024-04-12 14:23:00| 8.3| 0.0|ERROR |Error encountered while calling method `input'2024-04-12 14:23:00| 8.3| 0.0|FATAL |PythonCaller_7 (PythonFactory): PythonFactory failed to process feature
I trully do not understand what is going on. In general I need to get a list of all layers that are included in the webmap in Enterpise. I use SingleSingOn to log in to Esri Portal. I would appreciate help as noone seem to know the answer. I thouhg that maybe I can use Esri ArcGIS Online Connector to get this information but I apart from getting private_url of the webmap I cannot extract the information about the content of the webmap
A different way to do this is to use the ArcGISOnlineConnector to find the ItemId of the webmap, then use that ID to get the JSON of the WebMap.
Portal:
https://YourPortalUrl/portal/sharing/rest/content/items/YourItemId/data?f=json
ArcGIS Online:
https://www.arcgis.com/sharing/rest/content/items/YourItemId/data?f=json
Then put the json through a JSONFragmenter. Query is
json["operationalLayers"][*]
and set Flattening = Yes. Then expose what you need (id, title, url) using an AttributeExposer.
This is particularly relevant after the June 25th AGOL Upgrade. Where I used to select the layers and copy/paste from the Web Map Overview page into a spreadsheet for taking notes. That is no longer easy. And good luck getting a list of layers from a web map any other way. Community Forum wins again! :D
Because layers can be nested into groups etc. I use this function to loop to all the layers to get the urls:
def find_key(data, target_key, path="json"):
results = []
if isinstance(data, dict):
if target_key in data:
url = data[target_key]
item_id = data.get('itemId', None)
results.append((path, url, item_id))
for key, value in data.items():
new_path = f'{path}["{key}"]'
if isinstance(value, dict) or isinstance(value, list):
results.extend(find_key(value, target_key, new_path))
elif isinstance(data, list):
for index, item in enumerate(data):
new_path = f'{path}[{index}]'
if isinstance(item, dict) or isinstance(item, list):
results.extend(find_key(item, target_key, new_path))
return results
jsonKey = "url"
url_results = find_key(data, jsonKey)
for path, url, item_id in url_results:
end_of_string = None
if url is None:
match = False
print("url is Null")
else:
match = re.search(r'/(FeatureServer|MapServer)/(\d+)$', url)
if match:
end_of_string = match.group(2) # Capture the number at the end
url_stripped = re.sub(r'/(FeatureServer|MapServer)/\d+$', r'/\1', url)
else:
url_stripped = url
new_feature = fmeobjects.FMEFeature(feature)
new_feature.setAttribute('layer_url', url_stripped)
new_feature.setAttribute('layer_fullrl', url)
new_feature.setAttribute('layer_path', path)
if end_of_string is not None:
new_feature.setAttribute('layer_url_end', end_of_string)
if item_id is not None:
new_feature.setAttribute('layer_itemId', item_id)
self.pyoutput(new_feature)