How to ahref output of a GP Tool in WAB Geoprocessing Widget?

5328
3
Jump to solution
05-01-2016 02:42 PM
ThomasColson
MVP Frequent Contributor

With the python posted below, I have it attached to a model

Which has a parameter

Which runs successfully. I'm also able to successfully publish it as a GP Service.

Here's my first problem: Despite having a "Parameter", none is available to the Widget?

Second problem. When I execute the tool, I get this hungous url. What'd I really like is just the file name as a hyperlink to the full URL. Out of the box, the export web map (print to PDF) GP Tool does this nicely, why can't I make this work with this?

try:
    from xml.etree import cElementTree as ET
except:
    from xml.etree import ElementTree as ET
import arcpy, sys, traceback
from arcpy import env
import time, os
from subprocess import call
unicode = str


OutName = arcpy.GetParameterAsText(0)




fms = arcpy.FieldMappings()
fms.addTable("\\\\someserver\DATASTORE\GP\\RESTON FISH.sde\\FISH.DBO.FISH_BARRIERS")
FLD_STATION_NAME = arcpy.FieldMap()
FLD_STREAMNAME = arcpy.FieldMap()
FLD_EDITDATE = arcpy.FieldMap()


FLD_STATION_NAME.addInputField("\\\\someserver\DATASTORE\GP\\RESTON FISH.sde\\FISH.DBO.FISH_BARRIERS", "STATION_NAME")  
STATION_NAME_MAP = FLD_STATION_NAME.outputField  
STATION_NAME_MAP.name = "Name"  
FLD_STATION_NAME.outputField = STATION_NAME_MAP  
fms.addFieldMap(FLD_STATION_NAME)


FLD_STREAMNAME.addInputField("\\\\someserver\DATASTORE\GP\\RESTON FISH.sde\\FISH.DBO.FISH_BARRIERS", "STREAMNAME")  
STREAMNAME_MAP = FLD_STREAMNAME.outputField  
STREAMNAME_MAP.name = "Descript"  
FLD_STREAMNAME.outputField = STREAMNAME_MAP  
fms.addFieldMap(FLD_STREAMNAME)


FLD_EDITDATE.addInputField("\\\\someserver\DATASTORE\GP\\RESTON FISH.sde\\FISH.DBO.FISH_BARRIERS", "EDITDATE")  
EDITDATE_MAP = FLD_EDITDATE.outputField  
EDITDATE_MAP.name = "DateTimeS"
EDITDATE_MAP.type = "Text" 
FLD_EDITDATE.outputField = EDITDATE_MAP  
fms.addFieldMap(FLD_EDITDATE)


arcpy.FeatureClassToFeatureClass_conversion("\\\\someserver\DATASTORE\GP\\RESTON FISH.sde\\FISH.DBO.FISH_BARRIERS", "\\\\someserver\DATASTORE\GP\\", "FISH_BARRIERS.shp", "", fms)


gpx = ET.Element("gpx", xmlns="http://www.topografix.com/GPX/1/1",
                 xalan="http://xml.apache.org/xalan",
                 xsi="http://www.w3.org/2001/XMLSchema-instance",
                 creator="Esri",
                 version="1.1")




def prettify(elem):
    """Return a pretty-printed XML string for the Element.
    """
    from xml.dom import minidom
    rough_string = ET.tostring(elem, 'utf-8')
    reparsed = minidom.parseString(rough_string)
    return reparsed.toprettyxml(indent="  ")






def featuresToGPX(inputFC, outGPX, zerodate, pretty):
    ''' This is called by the __main__ if run from a tool or at the command line
    '''


    descInput = arcpy.Describe(inputFC)
    if descInput.spatialReference.factoryCode != 4326:
        arcpy.AddWarning("Input data is not projected in WGS84,"
                         " features were reprojected on the fly to create the GPX.")


    generatePointsFromFeatures(inputFC , descInput, zerodate)


    # Write the output GPX file
    try:
        if pretty:
            gpxFile = open(outGPX, "w")
            gpxFile.write(prettify(gpx))
        else:
            gpxFile = open(outGPX, "wb")
            ET.ElementTree(gpx).write(gpxFile, encoding="UTF-8", xml_declaration=True)
    except TypeError as e:
        arcpy.AddError("Error serializing GPX into the file.")
    finally:
        gpxFile.close()






def generatePointsFromFeatures(inputFC, descInput, zerodate=False):


    def attHelper(row):
        # helper function to get/set field attributes for output gpx file


        pnt = row[1].getPart()
        valuesDict["PNTX"] = str(pnt.X)
        valuesDict["PNTY"] = str(pnt.Y)


        Z = pnt.Z if descInput.hasZ else None
        if Z or ("ELEVATION" in cursorFields):
            valuesDict["ELEVATION"] = str(Z) if Z else str(row[fieldNameDict["ELEVATION"]])
        else:
            valuesDict["ELEVATION"] = str(0)


        valuesDict["NAME"] = row[fieldNameDict["NAME"]] if "NAME" in fields else " "
        valuesDict["DESCRIPT"] = row[fieldNameDict["DESCRIPT"]] if "DESCRIPT" in fields else " "




        if "DATETIMES" in fields:
            row_time = row[fieldNameDict["DATETIMES"]]
            formatted_time = row_time if row_time else " "
        elif zerodate and "DATETIMES" not in fields:
            formatted_time = time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime(0))
        else:
            formatted_time = time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime(0)) if zerodate else " "


        valuesDict["DATETIMES"] = formatted_time


        return
    #-------------end helper function-----------------




    def getValuesFromFC(inputFC, cursorFields ):


        previousPartNum = 0
        startTrack = True


        # Loop through all features and parts
        with arcpy.da.SearchCursor(inputFC, cursorFields, spatial_reference="4326", explode_to_points=True) as searchCur:
            for row in searchCur:
                if descInput.shapeType == "Polyline":
                    for part in row:
                        newPart = False
                        if not row[0] == previousPartNum or startTrack is True:
                            startTrack = False
                            newPart = True
                        previousPartNum = row[0]


                        attHelper(row)
                        yield "trk", newPart


                elif descInput.shapeType == "Multipoint" or descInput.shapeType == "Point":
                    # check to see if data was original GPX with "Type" of "TRKPT" or "WPT"
                    trkType = row[fieldNameDict["TYPE"]].upper() if "TYPE" in fields else None


                    attHelper(row)


                    if trkType == "TRKPT":
                        newPart = False
                        if previousPartNum == 0:
                            newPart = True
                            previousPartNum = 1


                        yield "trk", newPart


                    else:
                        yield "wpt", None


    # ---------end get values function-------------




    # Get list of available fields
    fields = [f.name.upper() for f in arcpy.ListFields(inputFC)]
    valuesDict = {"ELEVATION": 0, "NAME": "", "DESCRIPT": "", "DATETIMES": "", "TYPE": "", "PNTX": 0, "PNTY": 0}
    fieldNameDict = {"ELEVATION": 0, "NAME": 1, "DESCRIPT": 2, "DATETIMES": 3, "TYPE": 4, "PNTX": 5, "PNTY": 6}


    cursorFields = ["OID@", "SHAPE@"]


    for key, item in valuesDict.items():
        if key in fields:
            fieldNameDict[key] = len(cursorFields)  # assign current index
            cursorFields.append(key)   # build up list of fields for cursor
        else:
            fieldNameDict[key] = None


    for index, gpxValues in enumerate(getValuesFromFC(inputFC, cursorFields)):


        if gpxValues[0] == "wpt":
            wpt = ET.SubElement(gpx, 'wpt', {'lon':valuesDict["PNTX"], 'lat':valuesDict["PNTY"]})
            wptEle = ET.SubElement(wpt, "ele")
            wptEle.text = valuesDict["ELEVATION"]
            wptTime = ET.SubElement(wpt, "time")
            wptTime.text = valuesDict["DATETIMES"]
            wptName = ET.SubElement(wpt, "name")
            wptName.text = valuesDict["NAME"]
            wptDesc = ET.SubElement(wpt, "desc")
            wptDesc.text = valuesDict["DESCRIPT"]


        else:  #TRKS
            if gpxValues[1]:
                # Elements for the start of a new track
                trk = ET.SubElement(gpx, "trk")
                trkName = ET.SubElement(trk, "name")
                trkName.text = valuesDict["NAME"]
                trkDesc = ET.SubElement(trk, "desc")
                trkDesc.text = valuesDict["DESCRIPT"]
                trkSeg = ET.SubElement(trk, "trkseg")


            trkPt = ET.SubElement(trkSeg, "trkpt", {'lon':valuesDict["PNTX"], 'lat':valuesDict["PNTY"]})
            trkPtEle = ET.SubElement(trkPt, "ele")
            trkPtEle.text = valuesDict["ELEVATION"]
            trkPtTime = ET.SubElement(trkPt, "time")
            trkPtTime.text = valuesDict["DATETIMES"]






if __name__ == "__main__":
    ''' Gather tool inputs and pass them to featuresToGPX
    '''
    '''OutName = arcpy.GetParameterAsText(0)
    '''
    inputFC = "\\\\someserver\DATASTORE\GP\\FISH_BARRIERS.shp"
    outGPX = os.path.join(arcpy.env.scratchFolder, OutName)
    zerodate = "#"
    pretty = "#"
    featuresToGPX(inputFC, outGPX, zerodate, pretty)
    arcpy.Delete_management("\\\\someserver\DATASTORE\GP\\FISH_BARRIERS.shp")
0 Kudos
1 Solution

Accepted Solutions
RobertScheitlin__GISP
MVP Emeritus

Thomas,

   Maybe I am missing something here but it looks like you only have a output parameter and no input parameters so what are you missing in the GP widget UI that you are expecting to see? The second part of the long url link this is the default behavior of the widget and to modify that you will have to scour the code and find where the html anchor element is created in the widgets results and assign a different string instead of the complete url.

View solution in original post

3 Replies
RobertScheitlin__GISP
MVP Emeritus

Thomas,

   Maybe I am missing something here but it looks like you only have a output parameter and no input parameters so what are you missing in the GP widget UI that you are expecting to see? The second part of the long url link this is the default behavior of the widget and to modify that you will have to scour the code and find where the html anchor element is created in the widgets results and assign a different string instead of the complete url.

ThomasColson
MVP Frequent Contributor

Yup. That was the trick. By attaching this to a WAB GP Widget, and editing line 55 of resultRendererManger.js as such:

        text = '<a target="_blank" href="' + value.value.url + '">Get My Data</a>';

I'm able to do this:

0 Kudos
Arueira
New Contributor II

Hello everybody!
I don't know if I should post it here or open a new one, but my demand is similar, although I believe that what I'm wanting is what Thomas was getting in the beginning!

I created a python script in ArcGis Pro 3.1 where the final result is a Report from a Survey record.
In this script I programmed message sending at the beginning and end of processing.
I tested it on the desktop and it worked perfectly, I published it in Enterprise 10.9.1 and configured a geoprocess widget in an application with the web app builder and it also works, showing the processing start message in the "output" tab.
But, when finished, all information is erased and the screen is empty, not informing the user that processing has finished.
I was also unable to get a message with the name of the generated file and a link to it at the end of processing.
Where is the error? What to do?

0 Kudos