ironfelix717
Registered User.
- Local time
- Today, 06:00
- Joined
- Sep 20, 2019
- Messages
- 193
KML File Object for VBA
It is my pleasure to release the KMLFile object. With this class, you can read/write KML files with ease in VBA. Features include reading/writing the main sections of the file, extracting placemark objects and querying xpath on the file. This object is unique because it's versatility allows with a few lines of code to read or modify most KML files available. No longer does one need to painfully work with the crapshoot that is MSXML on a per-file basis. Download v1.0 11-9-22
Assumptions and Ground Rules
This object is is influenced by Google Earth's (GE) construction of a KML file. Advanced KML files that are used in non-GE systems may not be parse-able. It makes assumptions about a file's structure based on GE's way of doing things. The construction of a file can be briefly described in a sudo form below....
This object defines a KML file as having "sections" which can be read/written. Sections are defined below.
Object Breakdown
The following describes methods and properties of the object.
Usage Example:
Getting Placemarks Example:
(see documentation for KMLPlacemark Object)
Usage Comments:
A .kml file must be created or loaded into the object. When a file is created, it is automatically loaded into the object. Once the object is loaded, a user can read/write to individual sections of the file by setting properties. In simple terms, the object caches a copy of the file. A user may update properties to modify the contents of the file. Updates to the file via properties are applied to a cached copy of the file at time of property assignment. This is to say, the object applies edits to the cached copy in chronological order. The resulting updates are not reflected when reading properties back, UNTIL the file is saved. If the user calls the .Save() method and does not specify a destination, the original file is overwritten with the applied updates and re-loaded into the object. If an alternative destination is provided in .Save(), the user must re-load this alternative into the object to read updated properties.
All section properties that assign XML (XML, Document, Body, Styles) must be VALID XML! The system checks the validity at various points.
Developer Notes
It is necessary to provide a few words to developers who may consider working with XML/KML files. Using lazy string parsing on files (split functions, instr, mid), is obviously a poor practice when actual parsers are available (MSXML). One will find using "lazy" string parsing may work on one XML file--perhaps even two--but certainly the day will come when it fails. And probably sooner than later. Second, Replace() functions will NOT be reliable in modifying KML files to a degree of reliability this object performs at. This is especially true when attempting to replace strings that are an output of an IXMLDOMNODE, as the MSXML object has a tendency to output crap that wasn't the same as what you provided. In some cases, there are reasons for that. Such as, the GX namespace caused issue with the development of this project because its declaration is often MISSING from a node when processing. MSXML inserts namespace URIs when specified in a tag. An example of this may be
Credits
-- Developed by ironfelix717 Nov. 2022
Please reports bugs or issues in comments or dm.
Thanks to all who helped with issues.
https://stackoverflow.com - great resource for MSXML2 related info
https://learn.microsoft.com/en-us/previous-versions/troubleshoot/msxml/list-of-xml-parser-versions
https://developers.google.com/kml/documentation/kml_tut
https://developers.google.com/kml/documentation
It is my pleasure to release the KMLFile object. With this class, you can read/write KML files with ease in VBA. Features include reading/writing the main sections of the file, extracting placemark objects and querying xpath on the file. This object is unique because it's versatility allows with a few lines of code to read or modify most KML files available. No longer does one need to painfully work with the crapshoot that is MSXML on a per-file basis. Download v1.0 11-9-22
Assumptions and Ground Rules
This object is is influenced by Google Earth's (GE) construction of a KML file. Advanced KML files that are used in non-GE systems may not be parse-able. It makes assumptions about a file's structure based on GE's way of doing things. The construction of a file can be briefly described in a sudo form below....
Code:
<kml>
<Document>
<Styles>...
....
....
</Styles>
<Body>
....
....
</Body>
</Document>
</kml>
This object defines a KML file as having "sections" which can be read/written. Sections are defined below.
XML: Complete contents of the file.
Header: The KML/XML declaration at the top of a file. Data that is before the <Document> element begins.
Document: The <Document> element. The first and only child of the <kml> element.
Styles: Any child of the Document section which contains the tag name <Style> or <StyleMap>. Precedes the body.
Body: Any portion of the Document section which is not the Styles section. Includes placemarks and other elements, like folders. The bulk of the contents of a KML file.
Object Breakdown
The following describes methods and properties of the object.
Code:
.CreateNew(): [Sub] Creates a new KML file and is loaded into object.
.Load(): [Sub] Loads a pre-existing KML file into the object for reading/modifying.
.Query(): [Func] Allows an XPATH query for be ran on the unsaved state of the file (property updates included). Returns XML string. Xpath example: "\\kml\Document". Xpath queries are case sensitive!
Note: Problems with this function. Nodes beyond kml/Document are not findable after a document has been edited and saved with this object. This is due to erroneous indents at the top of the body section. Recommended use
of this function is to be used on a pre-existing file.
.Save(): [Func] Save the current file. Specify destination parameter to 'Save As'. Returns XML string of saved file.
.GetNamespace [Func] Retrieve the XML namespace URI from declarations (header).
.DebugString [Prop] Returns the instance's debug log. Cleared on Load(). Read only. Presence of a debug string does not indicate a fatal error and could be an internal warning. Nevertheless, worth investigating.
.AddToFolder [Sub] Creates a 'virtual' folder element to store XML strings in, such as built placemarks. Specify folder text and name of folder. if folder name does not exist, also creates new.
.GetFolderText [Func] Returns the text loaded into the folder which can then be assigned to a file section.
.XML: [Prop] Read XML or assign XML to the full file. Returns/Accepts XML string.
.Header [Prop] Read or assign the file's header (declaration section).
Index parameter is to specify which namespace is desired (default is KML namespace). 'URLOnly' returns the namespace without the xmlns prefix.
.Document [Prop] Read or assign new Document section. Returns/Accepts XML String.
.DocumentName [Prop] Reads or writes to the <name> attribute of the Document section. Returns/Accepts string.
.Styles [Prop] Read or assign new Styles section. Returns/Accepts XML String.
.GetPlacemarks() [Func] Returns a collection of KMLPlacemark objects found in the file. If none exist, returns empty collection. Optional parameters are
'FailOnError' - Fails if an internal error (runtime or debug error) is flagged. 'PreserveOnFail' - Retains a placemark instance's properties if an internal error occurs in an instance of a placemark object. See KMLPlacemark object documentation.
note: this function is resource intensive.
Usage Example:
Code:
Private Sub Example0()
Dim KFile As New KMLFile
'CREATE A FILE
With KFile
.CreateNew "\\Mac\Home\Desktop\My_New_File.kml"
.Body = "<Folder><name>My new folder</name></Folder>"
.Styles = "<Style>hello world</Style>"
.Save
Debug.Print .Body 'updated
End With
'LOAD A FILE
With KFile
.Load "\\Mac\Home\Desktop\My_New_File.kml"
Debug.Print .Body
End With
End Sub
Getting Placemarks Example:
(see documentation for KMLPlacemark Object)
Code:
Private Sub Example2()
'EXTRACTING PLACEMARK OBJECTS FROM FILE...
Dim P As KMLPlacemark
Dim KFile As New KMLFile
Dim Col As Collection
KFile.Load CurrentProject.Path & "\Example.kml"
Set Col = KFile.GetPlacemarks(True)
Debug.Print Col.Count
If Col.Count > 0 Then
For Each P In Col
Debug.Print P.PlacemarkName & ": " & P.Description
Debug.Print P.Coordinates
Debug.Print
Next P
End If
End Sub
Usage Comments:
A .kml file must be created or loaded into the object. When a file is created, it is automatically loaded into the object. Once the object is loaded, a user can read/write to individual sections of the file by setting properties. In simple terms, the object caches a copy of the file. A user may update properties to modify the contents of the file. Updates to the file via properties are applied to a cached copy of the file at time of property assignment. This is to say, the object applies edits to the cached copy in chronological order. The resulting updates are not reflected when reading properties back, UNTIL the file is saved. If the user calls the .Save() method and does not specify a destination, the original file is overwritten with the applied updates and re-loaded into the object. If an alternative destination is provided in .Save(), the user must re-load this alternative into the object to read updated properties.
All section properties that assign XML (XML, Document, Body, Styles) must be VALID XML! The system checks the validity at various points.
Developer Notes
It is necessary to provide a few words to developers who may consider working with XML/KML files. Using lazy string parsing on files (split functions, instr, mid), is obviously a poor practice when actual parsers are available (MSXML). One will find using "lazy" string parsing may work on one XML file--perhaps even two--but certainly the day will come when it fails. And probably sooner than later. Second, Replace() functions will NOT be reliable in modifying KML files to a degree of reliability this object performs at. This is especially true when attempting to replace strings that are an output of an IXMLDOMNODE, as the MSXML object has a tendency to output crap that wasn't the same as what you provided. In some cases, there are reasons for that. Such as, the GX namespace caused issue with the development of this project because its declaration is often MISSING from a node when processing. MSXML inserts namespace URIs when specified in a tag. An example of this may be
<gx:altitudeMode>[I]relativeToSeaFloor[/I]</gx:altitudeMode>
. MSXML inserts the namespace URI (whether declaration is missing or not) into the output XML. And this creates problems with parsing.Credits
-- Developed by ironfelix717 Nov. 2022
Please reports bugs or issues in comments or dm.
Thanks to all who helped with issues.
https://stackoverflow.com - great resource for MSXML2 related info
https://learn.microsoft.com/en-us/previous-versions/troubleshoot/msxml/list-of-xml-parser-versions
https://developers.google.com/kml/documentation/kml_tut
https://developers.google.com/kml/documentation