You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

datasource.py 4.7 KiB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. """
  2. DataSource is a wrapper for the OGR Data Source object, which provides
  3. an interface for reading vector geometry data from many different file
  4. formats (including ESRI shapefiles).
  5. When instantiating a DataSource object, use the filename of a
  6. GDAL-supported data source. For example, a SHP file or a
  7. TIGER/Line file from the government.
  8. The ds_driver keyword is used internally when a ctypes pointer
  9. is passed in directly.
  10. Example:
  11. ds = DataSource('/home/foo/bar.shp')
  12. for layer in ds:
  13. for feature in layer:
  14. # Getting the geometry for the feature.
  15. g = feature.geom
  16. # Getting the 'description' field for the feature.
  17. desc = feature['description']
  18. # We can also increment through all of the fields
  19. # attached to this feature.
  20. for field in feature:
  21. # Get the name of the field (e.g. 'description')
  22. nm = field.name
  23. # Get the type (integer) of the field, e.g. 0 => OFTInteger
  24. t = field.type
  25. # Returns the value the field; OFTIntegers return ints,
  26. # OFTReal returns floats, all else returns string.
  27. val = field.value
  28. """
  29. from ctypes import byref
  30. from django.contrib.gis.gdal.base import GDALBase
  31. from django.contrib.gis.gdal.driver import Driver
  32. from django.contrib.gis.gdal.error import GDALException, OGRIndexError
  33. from django.contrib.gis.gdal.layer import Layer
  34. from django.contrib.gis.gdal.prototypes import ds as capi
  35. from django.utils import six
  36. from django.utils.encoding import force_bytes, force_text
  37. from django.utils.six.moves import range
  38. # For more information, see the OGR C API source code:
  39. # http://www.gdal.org/ogr__api_8h.html
  40. #
  41. # The OGR_DS_* routines are relevant here.
  42. class DataSource(GDALBase):
  43. "Wraps an OGR Data Source object."
  44. def __init__(self, ds_input, ds_driver=False, write=False, encoding='utf-8'):
  45. # The write flag.
  46. if write:
  47. self._write = 1
  48. else:
  49. self._write = 0
  50. # See also http://trac.osgeo.org/gdal/wiki/rfc23_ogr_unicode
  51. self.encoding = encoding
  52. Driver.ensure_registered()
  53. if isinstance(ds_input, six.string_types):
  54. # The data source driver is a void pointer.
  55. ds_driver = Driver.ptr_type()
  56. try:
  57. # OGROpen will auto-detect the data source type.
  58. ds = capi.open_ds(force_bytes(ds_input), self._write, byref(ds_driver))
  59. except GDALException:
  60. # Making the error message more clear rather than something
  61. # like "Invalid pointer returned from OGROpen".
  62. raise GDALException('Could not open the datasource at "%s"' % ds_input)
  63. elif isinstance(ds_input, self.ptr_type) and isinstance(ds_driver, Driver.ptr_type):
  64. ds = ds_input
  65. else:
  66. raise GDALException('Invalid data source input type: %s' % type(ds_input))
  67. if ds:
  68. self.ptr = ds
  69. self.driver = Driver(ds_driver)
  70. else:
  71. # Raise an exception if the returned pointer is NULL
  72. raise GDALException('Invalid data source file "%s"' % ds_input)
  73. def __del__(self):
  74. "Destroys this DataStructure object."
  75. if self._ptr and capi:
  76. capi.destroy_ds(self._ptr)
  77. def __iter__(self):
  78. "Allows for iteration over the layers in a data source."
  79. for i in range(self.layer_count):
  80. yield self[i]
  81. def __getitem__(self, index):
  82. "Allows use of the index [] operator to get a layer at the index."
  83. if isinstance(index, six.string_types):
  84. l = capi.get_layer_by_name(self.ptr, force_bytes(index))
  85. if not l:
  86. raise OGRIndexError('invalid OGR Layer name given: "%s"' % index)
  87. elif isinstance(index, int):
  88. if index < 0 or index >= self.layer_count:
  89. raise OGRIndexError('index out of range')
  90. l = capi.get_layer(self._ptr, index)
  91. else:
  92. raise TypeError('Invalid index type: %s' % type(index))
  93. return Layer(l, self)
  94. def __len__(self):
  95. "Returns the number of layers within the data source."
  96. return self.layer_count
  97. def __str__(self):
  98. "Returns OGR GetName and Driver for the Data Source."
  99. return '%s (%s)' % (self.name, str(self.driver))
  100. @property
  101. def layer_count(self):
  102. "Returns the number of layers in the data source."
  103. return capi.get_layer_count(self._ptr)
  104. @property
  105. def name(self):
  106. "Returns the name of the data source."
  107. name = capi.get_ds_name(self._ptr)
  108. return force_text(name, self.encoding, strings_only=True)