Feature Request: pass optional dictionary of namespaces and optional doc type string
I extended the KML class so I could add a from_geojson function. Ideally this concept can be taken further to include other types such as shape files. The raw data formats dont have kml specific logic like xml doc type and namespaces. It would be very helpful if the to_string or constructor method had optional args that allow you to pass on the doctype and a dictionary of namespaces. The namespaces would also need to be passed along to the etree_element function. I had good results with this in my case.
In the below example I used inheritance to overwrite the parent. It assumes use of LXML.
def to_string(self, prettyprint=False, namespaces=None, doctype='<?xml version="1.0" encoding="UTF-8"?>') -> str:
"""Returns the KML object as a string."""
return etree.tostring(
self.etree_element(namespaces=namespaces),
encoding="utf-8",
pretty_print=prettyprint,
doctype=doctype,
).decode("UTF-8")
@cleder I'd like to work on this feature under Hacktoberfest. Can you please assign it to me?
Please have a look at the contributing guidelines.
I think instead of adding it to the to_string method, it would be better to add a save method to fastkml.kml.KML like the parse method, taking the file or filename to write to. I don't think you will need to pass the namespaces as @wesley-murray suggested, they are already present on the object.
In this context, I think it is worth a look if we want to register the namespaces on import time or when the object is serialized to XML -> https://github.com/cleder/fastkml/blob/develop/fastkml/config.py
@cleder I would like to give this a try. Can you assign me this issue?
@cleder Do we want to add "doctype" as a input parameter while trying to parse a KML file? OR Do we want to add a "save" functionality with "doctype" as an input parameter?
Stay close to the API fastkml is built on: A write function like lxml or xml.etree would do the trick
I think write should just take a pathlib.Path, not an open file. If the filename ends with .kmz the file should be zipped.
It should be a method of fastkml.kml.KML
e.g:
def write(self, file_name:pathlib.Path, *, pretty_print:bool=False, xml_declaration:bool=False) -> None:
Lxml:
The doctype option allows passing in a plain string that will be serialised before the XML tree. Note that passing in non well-formed content here will make the XML output non well-formed. Also, an existing doctype in the document tree will not be removed when serialising an ElementTree instance.
xml.etree:
xml_declaration=None, xml_declaration controls if an XML declaration should be added to the file. Use False for never, True for always, None for only if not US-ASCII or UTF-8 or Unicode (default is None)
I think true or false are enough for xml_declaration as it is either '<?xml version="1.0" encoding="UTF-8"?>' or '', no other doctypes are allowed anyway.
The other parameters that lxml or xml.etree define make not much sense for writing kml in 2024:
- encoding: who encodes in anything else than
UTF-8today? - method is always
xml
and some are not implemented in one of the two, e.g
- default_namespace (would always be
kmlin this case) - short_empty_elements (always true)
@wesley-murray what is the need for namespaces? When you create a fastkml object it always has name_spaces defined, defaulting to config.NAME_SPACES
Have a look at the documentation, the shapefile.__geo_interface__ exposes a GeoJson like interface.
created draft PR for this issue https://github.com/cleder/fastkml/pull/378
@cleder Created the PR.....let me know your thoughts on the write function implementation