Extract Feature Attachments

19722
32
10-24-2013 01:13 AM
Ranga_Tolapi
Occasional Contributor III
"Feature attachments" is the new feature from ArcGIS 10 on wards. How to extract feature attachments and save to disk using Python?
Tags (2)
0 Kudos
32 Replies
XanderBakker
Esri Esteemed Contributor
"Feature attachments" is the new feature from ArcGIS 10 on wards. How to extract feature attachments and save to disk using Python?


Hi,

In this blogpost (please read):
http://anothergisblog.blogspot.nl/2012/06/working-with-blob-data-at-101-arcpyda.html

... a nice example is included of how to read attachments:

from arcpy import da
import os
with da.SearchCursor(r"c:\temp\demo.gdb\table",['blobFieldname','fileName']) as cursor:
   for row in cursor:
      binaryRep = row[0]
      fileName = row[1]
      # save to disk
      open(r"c:\saveFolder" + os.sep + fileName, 'wb').write(binaryRep.tobytes())
      del row
      del binaryRep
      del fileName


You can find more on Cursor and blob fields (scroll down to end of page) through this link:
http://resources.arcgis.com/en/help/main/10.2/index.html#//002z0000001q000000

Kind regards,

Xander
0 Kudos
Ranga_Tolapi
Occasional Contributor III
Hi Xander,

Thanks for your response.

Actually I was looking about "Feature Attachments", which involves a relationship table to store the attachments for features.

Please go through "Query attachments" section in below link, which talks about performing the same task in .Net.

http://help.arcgis.com/en/sdk/10.0/arcobjects_net/conceptualhelp/index.html#//0001000001qr000000
0 Kudos
XanderBakker
Esri Esteemed Contributor
Hi Xander,

Thanks for your response.

Actually I was looking about "Feature Attachments", which involves a relationship table to store the attachments for features.

Please go through "Query attachments" section in below link, which talks about performing the same task in .Net.

http://help.arcgis.com/en/sdk/10.0/arcobjects_net/conceptualhelp/index.html#//0001000001qr000000


Python is more limited than ArcObjects (although you could implement COM types in Python and use ArcObjects). If you only want to save the attachments and not use any related data from the features then the code remains mostly the same:

from arcpy import da
import os
# fc = r"C:\Project\_LearnPython\Attachments\test.gdb\yourFCname"
tbl = r"C:\Project\_LearnPython\Attachments\test.gdb\yourFCname__ATTACH"
fldBLOB = 'DATA'
fldAttName = 'ATT_NAME'
outFolder = r"C:\Project\_LearnPython\Attachments"

with da.SearchCursor(tbl,[fldBLOB,fldAttName]) as cursor:
   for row in cursor:
      binaryRep = row[0]
      fileName = row[1]
      # save to disk
      open(outFolder + os.sep + fileName, 'wb').write(binaryRep.tobytes())
      del row
      del binaryRep
      del fileName


In this case you access the attachment tabel ("yourFCname__ATTACH"). The name of the attachment is stored in the field "ATT_NAME" and the binary data in the field "DATA".

If you want to access the feature itself, you will have to use the "REL_OBJECTID" field from the attachment table and query the featureclass on OBJECTID = REL_OBJECTID...

Kind regards,

Xander
Ranga_Tolapi
Occasional Contributor III
Thank you Xander, appreciated.
I will try this later, as I am busy with my other critical tasks.
0 Kudos
NicholasKnabe
New Contributor
How would I go about added the relationship data into my python script.

"If you want to access the feature itself, you will have to use the "REL_OBJECTID" field from the attachment table and query the featureclass on OBJECTID = REL_OBJECTID..."

I know you mentioned this way, but since it is a relationship does it need to be pathed to a geodatabase? Or how does it pull the relationship information with the pictures?

Thanks
-Nick
0 Kudos
MichaelVolz
Esteemed Contributor
Xander:

Would you be able to extend your code in python to be able to access images already stored as a BLOB field in SQL Server 2012 (non-GIS) as attachments without having to copy the images into ESRI feature classes thus eliminating data duplication of attachment files?
0 Kudos
XanderBakker
Esri Esteemed Contributor
How would I go about added the relationship data into my python script.

"If you want to access the feature itself, you will have to use the  "REL_OBJECTID" field from the attachment table and query the  featureclass on OBJECTID = REL_OBJECTID..."

I know you mentioned this way, but since it is a relationship does it  need to be pathed to a geodatabase? Or how does it pull the relationship  information with the pictures?



Hi Nicholas,

If you would like to access the related information the belongs to the attachment, you will have to use the REL_OBJECTID in the attachment table to query the feature class. In the code below I created a function "QueryRelatedData" that retrieves information from the feature class. If the related OID = 2, the expression will be "OBJECTID = 2", which is used as a query definition to only extract 1 feature. Next the attribute in the field "SomeFieldInFeatureClass" is accessed and returned.

I didn't test the code below, so be careful.

def main():
    global arcpy
    import arcpy, os

    # fixed settings
    fldBLOB = 'DATA'
    fldAttName = 'ATT_NAME'
    fldRelOID = 'REL_OBJECTID'

    # your settings (edit these)
    fc = r"C:\Project\_LearnPython\Attachments\test.gdb\Meldingen"
    tbl = r"C:\Project\_LearnPython\Attachments\test.gdb\Meldingen__ATTACH"
    outFolder = r"C:\Project\_LearnPython\Attachments"
    fldRelatedInfo = 'SomeFieldInFeatureClass' # should be valid column in FC

    with arcpy.da.SearchCursor(tbl,[fldBLOB,fldAttName,fldRelOID]) as cursor:
        for row in cursor:
            binaryRep = row[0]
            fileName = row[1]
            relOID = row[2]

            # access related information
            myRelatedInfo = QueryRelatedData(fc, fldRelatedInfo, relOID)
            # do something with the related info

            # save attachment to disk
            open(outFolder + os.sep + fileName, 'wb').write(binaryRep.tobytes())
            del row
            del binaryRep
            del fileName


def QueryRelatedData(fc, fldRelatedInfo, relOID):
    fldOID = 'OBJECTID'
    expression = arcpy.AddFieldDelimiters(fc, fldOID) + " = {0}".format(relOID)
    with arcpy.da.SearchCursor(fc, (fldOID, fldRelatedInfo), where_clause=expression) as cursor:
        for row in cursor:
            return row[1]
            break
        del row

if __name__ == '__main__':
    main()


Kind regards,

Xander
0 Kudos
TrilliumLevine1
Occasional Contributor

Hi Xander,

I'm working with this code sample in 10.2 to access related information from downloaded attachments.  The first problem I'm running into is that my myFeatureClass_ATTACH has no REL_OBJECTID field, only a REL_GLOBALID field.  When I adjust the code to use the expression to match the global id's instead of the object id's, I'm getting the following error:sqlerror.PNG

I'm not sure why it's still trying to select OBJECTID, which is maybe the problem (?) -- anyway, see my modified code below.  Please let me know if you have any ideas.  Any guidance is much appreciated!  Thanks -

Trill

def main():
    global arcpy
    import arcpy, os

    # fixed settings
    fldBLOB = 'DATA'
    fldAttName = 'ATT_NAME'
    fldRelGID = 'REL_GLOBALID'

    # your settings (edit these)
     ## related feature class
    fc = r"C:\Forstmobil_2014.12.01\Geodaten\Forstmobil_2014.12.01.gdb\Baumkontrolle_AGS_online"
    ## attachment table
    tbl = r"C:\Forstmobil_2014.12.01\Geodaten\Forstmobil_2014.12.01.gdb\Baumkontrolle_AGS_online__ATTACH
    fldRelatedInfo = 'CreationDate' # should be valid column in FC

    with arcpy.da.SearchCursor(tbl,[fldBLOB,fldAttName,fldRelGID]) as cursor:
        for row in cursor:
            binaryRep = row[0]
            fileName = row[1]
            relGID = row[2]
            # access related information
            myRelatedInfo = QueryRelatedData(fc, fldRelatedInfo, relGID)
            print myRelatedInfo

def QueryRelatedData(fc, fldRelatedInfo, relGID):
    fldGID = 'GlobalID'
    expression = arcpy.AddFieldDelimiters(fc, fldGID) + " = {0}".format(relGID)
    with arcpy.da.SearchCursor(fc, (fldGID, fldRelatedInfo), where_clause=expression) as cursor:
        for row in cursor:
            return row[1]
            break
        del row

if __name__ == '__main__':
    main()
0 Kudos
XanderBakker
Esri Esteemed Contributor

Strange, in your code there is no reference to the OBJECTID field. Maybe due to the attachments it is trying to include it, but if the relationship is based on GlobalID, then there will be no OBJECTID (?).

The only thing I saw missing is the quote at the end of line 14 (but I think that is a copy error).

0 Kudos