Address Data Management Solution; Using Your Schema

08-03-2020 03:08 PM
MVP Esteemed Contributor
2 5 2,321

I've been wrestling with the Address Data Management Solution for some time, and today, I finally got the toughest rule to work with my attributes: Split Intersecting Roads.  This rule is a really powerful editing tool as it will split an existing centerline into two segments when you add a new street that intersects it.  In essence it:


  1. Copies attributes from the original existing street to the 'new segment'
  2. Does a proportional division of the address ranges so you don't have to


To begin with, you need to  create a list of the attributes you want to copy during the split.  This is done near the top of the script:

The orginal looks like this:

var centerline_field_names = ["rclnguid", "discrpagid", "rangeprefixleft", "fromleft",
 "toleft", "parityleft", "rangeprefixright", "fromright", "toright", "parityright",
 "fullname","fedroute", "fedrtetype", "afedrte", "afedrtetype", "stroute", "strtetype",
 "astrte", "astrtetype", "ctyroute", "onewaydir", "roadlevel", "inwater", "roadclass",
 "countryleft", "countryright", "stateleft", "stateright", "countyleft",
 "countyright","munileft", "muniright", "zipleft", "zipright", "msagleft", "msagright",
 "esnleft", "esnright"]

Mine looks like this:

var centerline_field_names = ["FROMADDR_L","TOADDR_L","FROMADDR_R","TOADDR_R","PREDIR",

I used the arcpy.ListFields() function and a little text formatting in python to generate the list.  Something to take note of is the attribute names provided in the solution are all lower case and you can see mine are upper case as well as proper case. More on this further down. 


Any reference to the feature class name needs to be adjusted: 

There are two references to the feature class name:

var intersectingRoads = Intersects(FeatureSetByName($datastore, "RoadCenterline"), geom);

and down at the bottom of the script:

'edit': [{'className': 'RoadCenterline', 'adds': adds, 'updates': updates}]

Mine looks like this:

var intersectingRoads = Intersects(FeatureSetByName($datastore, "MSD.SLCOMSD.CenterlinesMSD"), geom);


edit': [{'className': 'MSD.SLCOMSD.CenterlinesMSD', 'adds': adds, 'updates': updates}]

My lines 11 and 15 show the full feature class name with Owner.Database as part of the name since I'm doing the edits in an Enterprise GBD (aka SDE); if you are using a file gdb, you'll only need the feature class name.


About midway down in the script, a series of variables are set to the field names where your address range info is stored:


The original references these attributes:

        // Get the address range of the intersecting road
        var fromRight = road.fromright;
        var toRight = road.toright;
        var fromLeft = road.fromleft;
        var toLeft = road.toleft;

While I reference:

        var fromRight = road.FROMADDR_R;
        var toRight = road.TOADDR_R;
        var fromLeft = road.FROMADDR_L;
        var toLeft = road.TOADDR_L;‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍


A little further down in the script, there are references again to the address range variables that get written to a dictionary:


The original:

  var attributes = {}
  if (newToFromRight[0] != null) attributes['toright'] = newToFromRight[0];
  if (newToFromLeft[0] != null) attributes['toleft'] = newToFromLeft[0];

And mine:

  var attributes = {}
  if (newToFromRight[0] != null) attributes['TOADDR_R'] = newToFromRight[0];
  if (newToFromLeft[0] != null) attributes['TOADDR_L'] = newToFromLeft[0];‍‍‍‍‍‍‍‍‍‍‍


As mentioned earlier, how you have your attribute names with respect to upper, lower, or proper case is an issue you need to deal with.  If all your field names are lower case, this isn't an issue for you.  But it is for me:


The original script uses a Lower() function three times:

        for (var k in featureAttributes) {
            if (Lower(k) == "fromright" && newToFromRight[1] != null) {
                newAttributes['fromright'] = newToFromRight[1];
            } else if (Lower(k) == "fromleft" && newToFromLeft[1] != null) {
                newAttributes['fromleft'] = newToFromLeft[1];
            } else if (IndexOf(centerline_field_names, Lower(k)) > -1 && featureAttributes != null) {
                newAttributes = featureAttributes;
            } else {

But the Lower() function trips with my schema, so I just remove them 
while again referencing my address range fields:

        var newAttributes = {};
        for (var k in featureAttributes) {
            if (k == "FROMADDR_R" && newToFromRight[1] != null) {
                newAttributes['FROMADDR_R'] = newToFromRight[1];
            } else if (k == "FROMADDR_L" && newToFromLeft[1] != null) {
                newAttributes['FROMADDR_L'] = newToFromLeft[1];
            } else if (IndexOf(centerline_field_names, k) > -1 && featureAttributes != null) {
                newAttributes = featureAttributes;
            } else {


Finally, I don't have a field called centerlineid but I do have field that is used in a similar fashion called UNIQUE_ID.  In the solution, the centerlines feature class related to the Alias Road Name table through the centerlineid field. And, that centerlineid field is updated with a Database Sequence.  If you plan to use centerlineid in your application, you are just fine.  However, if you are using another field name you'll need to perform a search and replace on centerlineid in the scipt and replace it with your attribute name.  You'll also need to add that attribute name to the Alias Road Name table so the relationship class works.


None of this would have been possible without a boat load of help and even more patience from Chris Fox‌.  Thanks Chris!

About the Author
Started with ArcInfo Version 4.5 on a Unix box, and have the gray hair to show for it. After spending several years in State Government I moved into the 911 dispatch arena. After a 14 year stint as a contract employee, I have returned to the public sector as GIS analyst in a metropolitan county in Utah.