exxamalte/python-georss-client

View on GitHub
georss_client/xml_parser/feed_item.py

Summary

Maintainability
A
3 hrs
Test Coverage
"""GeoRSS feed item."""
from __future__ import annotations

from georss_client.consts import (
    XML_TAG_GEO_LAT,
    XML_TAG_GEO_LONG,
    XML_TAG_GEO_POINT,
    XML_TAG_GEORSS_POINT,
    XML_TAG_GEORSS_POLYGON,
    XML_TAG_GEORSS_WHERE,
    XML_TAG_GML_EXTERIOR,
    XML_TAG_GML_LINEAR_RING,
    XML_TAG_GML_POINT,
    XML_TAG_GML_POLYGON,
    XML_TAG_GML_POS,
    XML_TAG_GML_POS_LIST,
    XML_TAG_GUID,
    XML_TAG_ID,
    XML_TAG_SOURCE,
)
from georss_client.xml_parser.feed_or_feed_item import FeedOrFeedItem
from georss_client.xml_parser.geometry import Geometry, Point, Polygon


class FeedItem(FeedOrFeedItem):
    """Represents a feed item."""

    def __repr__(self):
        """Return string representation of this feed item."""
        return f"<{self.__class__.__name__}({self.guid})>"

    @property
    def guid(self) -> str | None:
        """Return the guid of this feed item."""
        return self._attribute_with_text([XML_TAG_GUID, XML_TAG_ID])

    @property
    def id(self) -> str | None:
        """Return the id of this feed item."""
        return self.guid

    @property
    def source(self) -> str | None:
        """Return the source of this feed item."""
        return self._attribute([XML_TAG_SOURCE])

    @property
    def geometry(self) -> Geometry | None:
        """Return the geometry of this feed item."""
        # <georss:point>-0.5 119.8</georss:point>
        point = self._attribute([XML_TAG_GEORSS_POINT])
        if point:
            return Point(point[0], point[1])
        # GML
        where = self._attribute([XML_TAG_GEORSS_WHERE])
        if where:
            # Point:
            # <georss:where>
            #   <gml:Point>
            #     <gml:pos>44.11 -66.23</gml:pos>
            #   </gml:Point>
            # </georss:where>
            pos = self._attribute_in_structure(
                where, [XML_TAG_GML_POINT, XML_TAG_GML_POS]
            )
            if pos:
                return Point(pos[0], pos[1])
            # Polygon:
            # <georss:where>
            #   <gml:Polygon>
            #     <gml:exterior>
            #       <gml:LinearRing>
            #         <gml:posList>
            #           -71.106216 42.366661
            #           -71.105576 42.367104
            #           -71.104378 42.367134
            #           -71.103729 42.366249
            #           -71.098793 42.363331
            #           -71.101028 42.362541
            #           -71.106865 42.366123
            #           -71.106216 42.366661
            #         </gml:posList>
            #       </gml:LinearRing>
            #     </gml:exterior>
            #   </gml:Polygon>
            # </georss:where>
            pos_list = self._attribute_in_structure(
                where,
                [
                    XML_TAG_GML_POLYGON,
                    XML_TAG_GML_EXTERIOR,
                    XML_TAG_GML_LINEAR_RING,
                    XML_TAG_GML_POS_LIST,
                ],
            )
            if pos_list:
                return self._create_polygon(pos_list)
        # <geo:Point xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#">
        #   <geo:lat>38.3728</geo:lat>
        #   <geo:long>15.7213</geo:long>
        # </geo:Point>
        point = self._attribute([XML_TAG_GEO_POINT])
        if point:
            lat = point.get(XML_TAG_GEO_LAT)
            long = point.get(XML_TAG_GEO_LONG)
            if long and lat:
                return Point(lat, long)
        # <geo:long>119.948006</geo:long>
        # <geo:lat>-23.126413</geo:lat>
        lat = self._attribute([XML_TAG_GEO_LAT])
        long = self._attribute([XML_TAG_GEO_LONG])
        if long and lat:
            return Point(lat, long)
        # <georss:polygon>
        #   -34.937663524 148.597260613
        #   -34.9377026399999 148.597169138
        #   -34.9377002169999 148.59708737
        #   -34.9376945989999 148.59705595
        #   -34.9376863529999 148.596955098
        #   -34.937663524 148.597260613
        # </georss:polygon>
        polygon = self._attribute([XML_TAG_GEORSS_POLYGON])
        if polygon:
            # For now, only supporting the first polygon.
            if isinstance(polygon, list) and isinstance(polygon[0], list):
                polygon = polygon[0]
            return self._create_polygon(polygon)
        # None of the above
        return None

    @staticmethod
    def _create_polygon(coordinates):
        """Create a polygon from the provided coordinates."""
        if coordinates:
            if len(coordinates) % 2 != 0:
                # Not even number of coordinates - chop last entry.
                coordinates = coordinates[0 : len(coordinates) - 1]
            points = []
            for i in range(0, len(coordinates), 2):
                points.append(Point(coordinates[i], coordinates[i + 1]))
            return Polygon(points)
        return None