Display KML content

Keyhole Markup Language (KML) is an XML notation popularized by Google Earth and used to display geographic data for maps and scenes. KML is an extension of XML and uses a tag-based structure with nested elements and attributes. The KML file specifies a set of features (place marks, images, polygons, 3D models, textual descriptions, etc.) that can be displayed on maps in geospatial software implementing the KML encoding, include ArcGIS.

Along with geographic positioning information, KML files provide supporting content (including images and 3D models) and are often distributed in a zipped KMZ archive file. The contents of a KMZ file are a single root KML document (notionally "doc.kml") and optionally any overlays, images, icons, and COLLADA 3D models referenced in the KML, including network-linked KML files.

ArcGIS Runtime supports KML specification version 2.2 as defined by the Open GIS Consortium (OGC). Use the free Esri product ArcGIS Earth to read and write KML and KMZ files. See this Google KML Tutorial to learn more about the KML file structure, commonly used tags, and so on.

Display a KML/KMZ file

KML content is loaded using a KmlDataset . The KmlDataset constructor takes a URL, which can point to a local file or a network location. Loading the layer will cause the associated dataset to load. KML layers can also be loaded from portal items, which can specify a link to a file or the KML/KMZ file itself.

Use dark colors for code blocksCopy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277

KmlDataset kmlDataSource = new KmlDataset(kmlFilePathUri);
KmlLayer kmlOperationalLayer = new KmlLayer(kmlDataSource);

Many KML files are wrappers that point to resources over the network. For example, a weather map might consist of a single network link that points to the latest forecast, to be retrieved every five minutes. As a result, loading the layer does not necessarily guarantee that the content has loaded linked content can fail to load without affecting the load status of the layer.

Explore the KML content tree

KML layers contain content in a hierarchy. You may need to programmatically explore this hierarchy to interact with KML content. For example, to turn off a screen overlay, you would need to first find it in the tree, then change its visibility. This code will follow a recursive pattern, using a function that calls itself for each node in the tree. The KML tree should be explored starting with KmlDataset , which exposes the KML feature tree with the RootNodes property. This provides a collection of KmlNode objects.

Use dark colors for code blocksCopy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
private void ExploreKml(IEnumerable<KmlNode> nodes)
{
    foreach(KmlNode node in nodes)
    {
        // Do work here...
    }
}

The non-recursive part of turning off a screen overlay is toggling its visibility after it is found. Because you are working with a generic KmlNode , you first need to determine whether each iterated node is a KmlScreenOverlay . After the screen overlay is found, toggle its visibility.

Use dark colors for code blocksCopy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
private void ExploreKml(IEnumerable<KmlNode> nodes)
{
    foreach(KmlNode node in nodes)
    {
        if (node.GetType() == typeof(KmlScreenOverlay))
        {
            node.IsVisible = !node.IsVisible;
        }
    }
}

You should then look for screen overlay nodes that may exist deeper in the hierarchy, however. Recursively call the ExploreKml function (shown next) on any nodes that have children.

Use dark colors for code blocksCopy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
private void ExploreKml(IEnumerable<KmlNode> nodes)
{
    // Iterate all nodes.
    foreach (KmlNode node in nodes)
    {
        // Toggle node visibility for any screen overlays found.
        if (node.GetType() == typeof(KmlScreenOverlay))
        {
            node.IsVisible = !node.IsVisible;
        }

        // See if this node has child nodes; store them in a list.
        List<KmlNode> children = new List<KmlNode>();
        if (node is KmlContainer containerNode)
        {
            children.AddRange(containerNode.ChildNodes);
        }
        if (node is KmlNetworkLink networkLinkNode)
        {
            children.AddRange(networkLinkNode.ChildNodes);
        }

        // Recursively call this function with the child node list.
        ExploreKml(children);
    }
}
You can call the recursive function initially with the KmlDataset RootNodes method, either after loading the map or in reaction to user action (such as a button press).

The tree-exploration pattern is useful for other tasks involving KML. For example, ArcGIS Earth uses a recursive pattern to build a table of contents:

KML content tree

Identify and popups in KML

In the ArcGIS information model, a popup is defined with a set of fields that describe an object, including how that information is formatted. Unlike ArcGIS feature services, KML files don't define a standard schema for object attributes. Instead, KML files may provide a rich HTML annotation for each object, which can be presented in place of a popup. You can access the HTML annotation via KmlNode .BalloonContent and then display that using a web view.

Viewpoints in KML

The OGC KML specification has two primary ways for defining viewpoints:

  • LookAt - defines a camera relative to the position of a KML feature

  • Camera - defines the position of the camera explicitly

The Runtime KmlViewpoint class can represent both types of viewpoints. Custom code is required to convert from a KML viewpoint to an ArcGIS Runtime viewpoint, which can be used for navigating a scene. See Google's reference documentation for details, including diagrams. Earth browsing apps should respect LookAt viewpoints specified in KML content.

Use dark colors for code blocksCopy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
    KmlViewpoint kvp = node.Viewpoint;
    // If KmlViewpoint is specified, use it.
    if (kvp != null)
    {
        // Altitude adjustment is needed for everything except Absolute altitude mode.
        needsAltitudeFix = (kvp.AltitudeMode != KmlAltitudeMode.Absolute);
        switch (kvp.Type)
        {
            case KmlViewpointType.LookAt:
                return new Viewpoint(kvp.Location,
                    new Camera(kvp.Location, kvp.Range, kvp.Heading, kvp.Pitch, kvp.Roll));
            case KmlViewpointType.Camera:
                return new Viewpoint(kvp.Location,
                    new Camera(kvp.Location, kvp.Heading, kvp.Pitch, kvp.Roll));
            default:
                throw new InvalidOperationException("Unexpected KmlViewPointType: " + kvp.Type);
        }
    }

Play KML tours

ArcGIS Runtime supports playing tours contained in KML files. A KML tour defines a map exploration experience that can contain: narration and music, animated movement between viewpoints, and dynamic animation of KML feature properties.

To play a KML tour, create a KmlTourController and set its Tour property to the tour you want to play. Then use the Play, Pause, and Restart methods on KmlTourController to work with the tour. If the tour contains audio, that audio will play automatically with the tour. To monitor the status of the tour, you can check to the TourStatus property on KmlTour .

The following example shows a function that can search KML nodes for a tour and assign the first one it finds to a KmlTourController .

See Touring in KML on the Google developers site to learn more about KML Tours.

Use dark colors for code blocksCopy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
// The KML tour controller provides player controls for KML tours.
private readonly KmlTourController _tourController = new KmlTourController();

// A function to search KML nodes and find a tour.
private void FindKmlTour(IEnumerable<KmlNode> rootNodes)
{
    // Hold a list of nodes to explore.
    Queue<KmlNode> nodesToExplore = new Queue<KmlNode>();

    // Add each root node to the list.
    foreach (KmlNode rootNode in rootNodes)
    {
        nodesToExplore.Enqueue(rootNode);
    }

    // Keep exploring until a tour is found or there are no more nodes.
    while (nodesToExplore.Any())
    {
        // Remove a node from the queue.
        KmlNode currentNode = nodesToExplore.Dequeue();

        // If the node is a tour, assign it to the tour controller.
        if (currentNode is KmlTour)
        {
            _tourController.Tour = (KmlTour) currentNode;
            return;
        }

        // If the node is a container, add all of its children to the list of nodes to explore.
        if (currentNode is KmlContainer)
        {
            KmlContainer container = (KmlContainer) currentNode;
            foreach (KmlNode node in container.ChildNodes)
            {
                nodesToExplore.Enqueue(node);
            }
        }
    }
}

Samples

Display KML

List KML contents

Identify KML features

Play KML tour

Display KML network links

Edit KML ground overlay

Create and save KML file

Your browser is no longer supported. Please upgrade your browser for the best experience. See our browser deprecation post for more details.