Retrieve the stream network visualization in KML format.

        Args:
            session (:mod:`sqlalchemy.orm.session.Session`): SQLAlchemy session object bound to PostGIS enabled database
            path (str, optional): Path to file where KML will be written. Defaults to None.
            documentName (str, optional): Name of the KML document. This will be the name that appears in the legend.
                Defaults to 'Stream Network'.
            withNodes (bool, optional): Include nodes. Defaults to False.
            styles (dict, optional): Custom styles to apply to KML geometry. Defaults to empty dictionary.

                Valid keys (styles) include:
                   * lineColor: tuple/list of RGBA integers (0-255) e.g.: (255, 0, 0, 128)
                   * lineWidth: float line width in pixels
                   * nodeIconHref: link to icon image (PNG format) to represent nodes (see: http://kml4earth.appspot.com/icons.html)
                   * nodeIconScale: scale of the icon image

        Returns:
            str: KML string

def getStreamNetworkAsKml(self, session, path=None, documentName='Stream Network', withNodes=False, styles={}):
        """
        Retrieve the stream network visualization in KML format.

        Args:
            session (:mod:`sqlalchemy.orm.session.Session`): SQLAlchemy session object bound to PostGIS enabled database
            path (str, optional): Path to file where KML will be written. Defaults to None.
            documentName (str, optional): Name of the KML document. This will be the name that appears in the legend.
                Defaults to 'Stream Network'.
            withNodes (bool, optional): Include nodes. Defaults to False.
            styles (dict, optional): Custom styles to apply to KML geometry. Defaults to empty dictionary.

                Valid keys (styles) include:
                   * lineColor: tuple/list of RGBA integers (0-255) e.g.: (255, 0, 0, 128)
                   * lineWidth: float line width in pixels
                   * nodeIconHref: link to icon image (PNG format) to represent nodes (see: http://kml4earth.appspot.com/icons.html)
                   * nodeIconScale: scale of the icon image

        Returns:
            str: KML string
        """
        # Retrieve Stream Links
        links = self.getFluvialLinks()

        # Set Default Styles
        lineColorValue = (255, 255, 0, 0)  # Blue
        lineWidthValue = 2
        nodeIconHrefValue = 'http://maps.google.com/mapfiles/kml/paddle/red-circle.png'
        nodeIconScaleValue = 1.0

        if 'lineColor' in styles:
            if len(styles['lineColor']) < 4:
                log.warning('lineColor style must be a list or a tuple of four elements containing integer RGBA values.')
            else:
                userLineColor = styles['lineColor']
                lineColorValue = (userLineColor[3], userLineColor[2], userLineColor[1], userLineColor[0])

        if 'lineWidth' in styles:
            try:
                float(styles['lineWidth'])
                lineWidthValue = styles['lineWidth']

            except ValueError:
                log.warning('lineWidth must be a valid number containing the width of the line in pixels.')

        if 'nodeIconHref' in styles:
            nodeIconHrefValue = styles['nodeIconHref']

        if 'nodeIconScale' in styles:
            try:
                float(styles['nodeIconScale'])
                nodeIconScaleValue = styles['nodeIconScale']

            except ValueError:
                log.warning('nodeIconScaleValue must be a valid number containing the width of the line in pixels.')


        # Initialize KML Document
        kml = ET.Element('kml', xmlns='http://www.opengis.net/kml/2.2')
        document = ET.SubElement(kml, 'Document')
        docName = ET.SubElement(document, 'name')
        docName.text = documentName

        for link in links:
            placemark = ET.SubElement(document, 'Placemark')
            placemarkName = ET.SubElement(placemark, 'name')
            placemarkName.text = str(link.linkNumber)

            # Create style tag and setup styles
            styles = ET.SubElement(placemark, 'Style')

            # Set line style
            lineStyle = ET.SubElement(styles, 'LineStyle')
            lineColor = ET.SubElement(lineStyle, 'color')
            lineColor.text = '%02X%02X%02X%02X' % lineColorValue
            lineWidth = ET.SubElement(lineStyle, 'width')
            lineWidth.text = str(lineWidthValue)

            # Add the geometry to placemark
            linkKML = link.getAsKml(session)
            if linkKML:
                lineString = ET.fromstring(linkKML)
                placemark.append(lineString)
            else:
                log.warning("No geometry found for link with id {0}".format(link.id))

            if withNodes:
                # Create the node styles
                nodeStyles = ET.SubElement(document, 'Style', id='node_styles')

                # Hide labels
                nodeLabelStyle = ET.SubElement(nodeStyles, 'LabelStyle')
                nodeLabelScale = ET.SubElement(nodeLabelStyle, 'scale')
                nodeLabelScale.text = str(0)

                # Style icon
                nodeIconStyle = ET.SubElement(nodeStyles, 'IconStyle')

                # Set icon
                nodeIcon = ET.SubElement(nodeIconStyle, 'Icon')
                iconHref = ET.SubElement(nodeIcon, 'href')
                iconHref.text = nodeIconHrefValue

                # Set icon scale
                iconScale = ET.SubElement(nodeIconStyle, 'scale')
                iconScale.text = str(nodeIconScaleValue)

                for node in link.nodes:
                    # New placemark for each node
                    nodePlacemark = ET.SubElement(document, 'Placemark')
                    nodePlacemarkName = ET.SubElement(nodePlacemark, 'name')
                    nodePlacemarkName.text = str(node.nodeNumber)

                    # Styles for the node
                    nodeStyleUrl = ET.SubElement(nodePlacemark, 'styleUrl')
                    nodeStyleUrl.text = '#node_styles'

                    nodeString = ET.fromstring(node.getAsKml(session))
                    nodePlacemark.append(nodeString)

                    # Embed node data
                    nodeExtendedData = ET.SubElement(nodePlacemark, 'ExtendedData')

                    nodeNumberData = ET.SubElement(nodeExtendedData, 'Data', name='node_number')
                    nodeNumberValue = ET.SubElement(nodeNumberData, 'value')
                    nodeNumberValue.text = str(node.nodeNumber)

                    nodeLinkNumberData = ET.SubElement(nodeExtendedData, 'Data', name='link_number')
                    nodeLinkNumberValue = ET.SubElement(nodeLinkNumberData, 'value')
                    nodeLinkNumberValue.text = str(link.linkNumber)

                    nodeElevationData = ET.SubElement(nodeExtendedData, 'Data', name='elevation')
                    nodeElevationValue = ET.SubElement(nodeElevationData, 'value')
                    nodeElevationValue.text = str(node.elevation)

            # Create the data tag
            extendedData = ET.SubElement(placemark, 'ExtendedData')

            # Add value to data
            linkNumberData = ET.SubElement(extendedData, 'Data', name='link_number')
            linkNumberValue = ET.SubElement(linkNumberData, 'value')
            linkNumberValue.text = str(link.linkNumber)

            linkTypeData = ET.SubElement(extendedData, 'Data', name='link_type')
            linkTypeValue = ET.SubElement(linkTypeData, 'value')
            linkTypeValue.text = str(link.type)

            numElementsData = ET.SubElement(extendedData, 'Data', name='number_elements')
            numElementsValue = ET.SubElement(numElementsData, 'value')
            numElementsValue.text = str(link.numElements)

            dxData = ET.SubElement(extendedData, 'Data', name='dx')
            dxValue = ET.SubElement(dxData, 'value')
            dxValue.text = str(link.dx)

            erodeData = ET.SubElement(extendedData, 'Data', name='erode')
            erodeValue = ET.SubElement(erodeData, 'value')
            erodeValue.text = str(link.type)

            subsurfaceData = ET.SubElement(extendedData, 'Data', name='subsurface')
            subsurfaceValue = ET.SubElement(subsurfaceData, 'value')
            subsurfaceValue.text = str(link.type)

        kmlString = ET.tostring(kml)

        if path:
            with open(path, 'w') as f:
                f.write(kmlString)

        return kmlString