Hello,
I have a python script that I use to publish map and image services to an ArcGIS Enterprise server for my organization, and the script involve creating an .sddraft file, modifying the XML in the .sddraft file, transforming it to a service definition file, then publishing it.
I was wondering if the XML schema for the .sddraft file is documented anywhere? My modifications to the .sddraft file are based on what I find on other ESRI forum posts and documentation, but there are some settings that I don’t know how to configure since I don’t know the XML schema.
Is there a better way to achieve what I am trying to do? If there’s a better approach with a simpler interface that would be wonderful.
I am using ArcPro 3.0 and publishing to ArcGIS Server 10.9.1
Here is the code:
import arcpy
import codecs
import getpass
import logging
import os
import sys
import shutil
import tempfile
import xml.dom.minidom as DOM
from pathlib import Path
from arcgis.gis.server import Server
ags_pw = getpass.getpass("ArcGIS server password: ")
ags_host = "https://localhost:6443"
ags_user = "admin"
project_filename = f"samples/my_example.aprx"
svc_name = "my_example"
def setText(doc, node, newText):
textnode = doc.createTextNode(newText)
node.appendChild(textnode)
tmp_sd_pth = os.path.join(os.getcwd(), "tmp.sd")
with tempfile.TemporaryDirectory() as tmp_dir:
tmp_pth = Path(tmp_dir)
sd_draft_fn = tmp_pth.joinpath("tempdraft.sddraft")
new_sd_draft = tmp_pth.joinpath("updatedDraft.sddraft")
sd = tmp_pth.joinpath(f"{svc_name}.sd")
mapdoc = arcpy.mp.ArcGISProject(project_filename)
maps = mapdoc.listMaps()
map = mapdoc.listMaps()[0]
sd_draft = arcpy.sharing.CreateSharingDraft("STANDALONE_SERVER", "MAP_SERVICE", svc_name, map)
sd_draft.offline = True
sd_draft.offlineTarget = "ENTERPRISE_10x"
sd_draft.description = "Description"
sd_draft.serverFolder = "maps"
sd_draft.overwriteExistingService = True
sd_draft.exportToSDDraft(sd_draft_fn)
doc = DOM.parse(sd_draft_fn.as_posix())
tagsType = doc.getElementsByTagName('Type')
for tagType in tagsType:
if tagType.parentNode.tagName == 'SVCManifest':
if tagType.hasChildNodes():
tagType.firstChild.data = "esriServiceDefinitionType_Replacement"
tagsState = doc.getElementsByTagName('State')
for tagState in tagsState:
if tagState.parentNode.tagName == 'SVCManifest':
if tagState.hasChildNodes():
tagState.firstChild.data = "esriSDState_Published"
# Turn off caching
configProps = doc.getElementsByTagName('ConfigurationProperties')[0]
propArray = configProps.firstChild
propSets = propArray.childNodes
for propSet in propSets:
keyValues = propSet.childNodes
for keyValue in keyValues:
if keyValue.tagName == 'Key':
if keyValue.firstChild.data == "isCached":
keyValue.nextSibling.firstChild.data = "false"
if keyValue.firstChild.data == "maxRecordCount":
keyValue.nextSibling.firstChild.data = "2000"
# Find all elements named TypeName
# This is where the extensions are defined
typeNames = doc.getElementsByTagName('TypeName')
for typeName in typeNames:
if typeName.firstChild.data == "KmlServer":
extension = typeName.parentNode
for extElement in extension.childNodes:
if extElement.tagName == 'Enabled':
extElement.firstChild.data = 'true'
if typeName.firstChild.data == "WFSServer":
extension = typeName.parentNode
for extElement in extension.childNodes:
if extElement.tagName == 'Enabled':
extElement.firstChild.data = 'true'
if typeName.firstChild.data == "WMSServer":
extension = typeName.parentNode
for extElement in extension.childNodes:
if extElement.tagName == 'Enabled':
extElement.firstChild.data = 'true'
if typeName.firstChild.data == "WCSServer":
extension = typeName.parentNode
for extElement in extension.childNodes:
if extElement.tagName == 'Enabled':
extElement.firstChild.data = 'true'
if typeName.firstChild.data == "FeatureServer":
extension = typeName.parentNode
for extElement in extension.childNodes:
if extElement.tagName == 'Enabled':
extElement.firstChild.data = 'true'
configProps = doc.getElementsByTagName('Info')[0]
propArray = configProps.firstChild
propSets = propArray.childNodes
for propSet in propSets:
keyValues = propSet.childNodes
for keyValue in keyValues:
if keyValue.tagName == 'Key':
if keyValue.firstChild.data == "WebCapabilities":
keyValue.nextSibling.firstChild.data = "Map,Data,Query"
typeNames = doc.getElementsByTagName('TypeName')
for typeName in typeNames:
if typeName.firstChild.data == "WFSServer":
extension = typeName.parentNode
for extElement in extension.childNodes:
if extElement.tagName == "Props":
for propSet in extElement.childNodes:
for prop in propSet.childNodes:
for prop1 in prop.childNodes:
if prop1.tagName == "Key":
if prop1.firstChild.data == "title":
setText(doc, prop1.nextSibling, "Example")
if prop1.firstChild.data == "abstract":
setText(doc, prop1.nextSibling, "Abstract")
if prop1.firstChild.data == "keyword":
setText(doc, prop1.nextSibling, "Keyword")
# Write to a new .sddraft file
with codecs.open(new_sd_draft, "w", "utf-8") as f:
doc.writexml(writer=f, encoding="utf-8")
logging.info("Analyzing and Staging the service...")
arcpy.server.StageService(new_sd_draft.as_posix(), sd.as_posix())
warnings = arcpy.GetMessages(1)
errors = arcpy.GetMessages(2)
if errors:
logging.error("errors found in service definition")
logging.error(errors)
sys.exit(1)
shutil.copyfile(sd, tmp_sd_pth)
server = Server(url=f"{ags_host}/arcgis/admin", token_url=f"{ags_host}/arcgis/tokens/generateToken", username=ags_user, password=ags_pw)
pr = server.publish_sd(tmp_sd_pth)
if pr:
logging.info(f"Service was successfully published")
else:
logging.error("Failed to publish service")
Solved! Go to Solution.
Great question!
Thank you for sharing your code.
The following will output a sample sddraft xml document to the directory the script is in.
You can then view the xml with an IDE.
def prettify_xml(doc):
"""Pretty-print an XML document, removing unnecessary blank lines."""
return '\n'.join([line for line in doc.toprettyxml(indent=" ").splitlines() if line.strip()])
pretty_xml = prettify_xml(doc)
with open("sample_sddraft.xml", "w", encoding="utf-8") as file:
file.write(pretty_xml)
Great question!
Thank you for sharing your code.
The following will output a sample sddraft xml document to the directory the script is in.
You can then view the xml with an IDE.
def prettify_xml(doc):
"""Pretty-print an XML document, removing unnecessary blank lines."""
return '\n'.join([line for line in doc.toprettyxml(indent=" ").splitlines() if line.strip()])
pretty_xml = prettify_xml(doc)
with open("sample_sddraft.xml", "w", encoding="utf-8") as file:
file.write(pretty_xml)