0
# XML Utilities
1
2
Tools for creating, parsing, and manipulating XML documents and NETCONF payloads. NCClient provides a comprehensive XML toolkit with namespace support, NETCONF-specific helpers, and efficient parsing capabilities.
3
4
## Capabilities
5
6
### XML Element Creation
7
8
Functions for creating XML elements and building XML documents programmatically.
9
10
```python { .api }
11
def new_ele(tag, attrs=None, **extra):
12
"""
13
Create new XML element.
14
15
Parameters:
16
- tag: str, element tag name (may include namespace)
17
- attrs: dict, element attributes
18
- **extra: additional attributes as keyword arguments
19
20
Returns:
21
Element: New XML element
22
"""
23
24
def new_ele_ns(tag, ns, attrs=None, **extra):
25
"""
26
Create new XML element with explicit namespace.
27
28
Parameters:
29
- tag: str, element tag name
30
- ns: str, namespace URI
31
- attrs: dict, element attributes
32
- **extra: additional attributes as keyword arguments
33
34
Returns:
35
Element: New namespaced XML element
36
"""
37
38
def sub_ele(parent, tag, attrs=None, **extra):
39
"""
40
Create XML sub-element under parent.
41
42
Parameters:
43
- parent: Element, parent element
44
- tag: str, sub-element tag name
45
- attrs: dict, element attributes
46
- **extra: additional attributes as keyword arguments
47
48
Returns:
49
Element: New sub-element
50
"""
51
52
def sub_ele_ns(parent, tag, ns, attrs=None, **extra):
53
"""
54
Create namespaced XML sub-element under parent.
55
56
Parameters:
57
- parent: Element, parent element
58
- tag: str, sub-element tag name
59
- ns: str, namespace URI
60
- attrs: dict, element attributes
61
- **extra: additional attributes as keyword arguments
62
63
Returns:
64
Element: New namespaced sub-element
65
"""
66
```
67
68
### XML Parsing
69
70
Functions for parsing XML documents and converting between formats.
71
72
```python { .api }
73
def parse_root(raw):
74
"""
75
Parse XML document and return root element.
76
77
Parameters:
78
- raw: str or bytes, XML document content
79
80
Returns:
81
Element: Root element of parsed document
82
"""
83
84
def to_xml(ele, encoding="UTF-8", pretty_print=False):
85
"""
86
Convert XML element to string representation.
87
88
Parameters:
89
- ele: Element, XML element to convert
90
- encoding: str, character encoding (default UTF-8)
91
- pretty_print: bool, format with indentation
92
93
Returns:
94
str: XML string representation
95
"""
96
97
def to_ele(x):
98
"""
99
Convert various inputs to XML element.
100
101
Parameters:
102
- x: str, bytes, file-like object, or Element
103
104
Returns:
105
Element: XML element
106
"""
107
```
108
109
### XML Validation and Utilities
110
111
Helper functions for XML validation and manipulation.
112
113
```python { .api }
114
def validate_xml(xml_string, schema=None):
115
"""
116
Validate XML against schema.
117
118
Parameters:
119
- xml_string: str, XML content to validate
120
- schema: Schema object, validation schema (optional)
121
122
Returns:
123
bool: True if valid, False otherwise
124
"""
125
126
def unqualify(tag):
127
"""
128
Remove namespace qualification from tag name.
129
130
Parameters:
131
- tag: str, qualified tag name
132
133
Returns:
134
str: Unqualified tag name
135
"""
136
137
def qualify(tag, ns=None):
138
"""
139
Add namespace qualification to tag name.
140
141
Parameters:
142
- tag: str, tag name to qualify
143
- ns: str, namespace URI
144
145
Returns:
146
str: Qualified tag name
147
"""
148
```
149
150
## XML Parsers
151
152
Parser objects for handling different XML processing requirements.
153
154
```python { .api }
155
# Standard XML parser
156
parser = etree.XMLParser(recover=False)
157
158
# Parser with huge tree support for large documents
159
huge_parser = etree.XMLParser(recover=False, huge_tree=True)
160
161
def _get_parser(huge_tree=False):
162
"""
163
Get appropriate parser based on requirements.
164
165
Parameters:
166
- huge_tree: bool, whether to use huge tree support
167
168
Returns:
169
XMLParser: Configured XML parser
170
"""
171
```
172
173
## Namespace Constants
174
175
Predefined namespace URIs for common NETCONF and network management schemas.
176
177
```python { .api }
178
# Base NETCONF namespace (RFC 6241)
179
BASE_NS_1_0 = "urn:ietf:params:xml:ns:netconf:base:1.0"
180
181
# YANG namespace (RFC 6020/7950)
182
YANG_NS_1_0 = "urn:ietf:params:xml:ns:yang:1"
183
184
# Cisco NXOS namespaces
185
NXOS_1_0 = "http://www.cisco.com/nxos:1.0"
186
NXOS_IF = "http://www.cisco.com/nxos:1.0:if_manager"
187
CISCO_CPI_1_0 = "http://www.cisco.com/cpi_10/schema"
188
189
# Juniper namespace
190
JUNIPER_1_1 = "http://xml.juniper.net/xnm/1.1/xnm"
191
192
# Huawei namespaces
193
HUAWEI_NS = "http://www.huawei.com/netconf/vrp"
194
HW_PRIVATE_NS = "http://www.huawei.com/netconf/capability/base/1.0"
195
196
# H3C namespaces
197
H3C_DATA_1_0 = "http://www.h3c.com/netconf/data:1.0"
198
H3C_CONFIG_1_0 = "http://www.h3c.com/netconf/config:1.0"
199
H3C_ACTION_1_0 = "http://www.h3c.com/netconf/action:1.0"
200
201
# Nokia/Alcatel-Lucent namespaces
202
ALU_CONFIG = "urn:alcatel-lucent.com:sros:ns:yang:conf-r13"
203
SROS_GLOBAL_OPS_NS = "urn:nokia.com:sros:ns:yang:sr:oper-global"
204
205
# NETCONF standard namespaces
206
NETCONF_MONITORING_NS = "urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring"
207
NETCONF_NOTIFICATION_NS = "urn:ietf:params:xml:ns:netconf:notification:1.0"
208
NETCONF_WITH_DEFAULTS_NS = "urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults"
209
210
# Tail-f namespaces
211
TAILF_AAA_1_1 = "http://tail-f.com/ns/aaa/1.1"
212
TAILF_EXECD_1_1 = "http://tail-f.com/ns/execd/1.1"
213
214
# Flowmon namespace
215
FLOWMON_1_0 = "http://www.liberouter.org/ns/netopeer/flowmon/1.0"
216
```
217
218
## XML Error Handling
219
220
Exception classes for XML processing errors.
221
222
```python { .api }
223
class XMLError(NCClientError):
224
"""Exception for XML processing errors."""
225
226
def __init__(self, message, xml_content=None):
227
"""
228
Initialize XML error.
229
230
Parameters:
231
- message: str, error description
232
- xml_content: str, XML content that caused error (optional)
233
"""
234
```
235
236
## NETCONF XML Helpers
237
238
Specialized functions for NETCONF-specific XML operations.
239
240
```python { .api }
241
def build_filter(spec, filter_type="subtree"):
242
"""
243
Build NETCONF filter element.
244
245
Parameters:
246
- spec: str or tuple, filter specification
247
- filter_type: str, filter type ('subtree' or 'xpath')
248
249
Returns:
250
Element: NETCONF filter element
251
"""
252
253
def build_rpc(operation, *args, **kwargs):
254
"""
255
Build NETCONF RPC element.
256
257
Parameters:
258
- operation: str, RPC operation name
259
- *args: positional arguments for operation
260
- **kwargs: keyword arguments for operation
261
262
Returns:
263
Element: NETCONF RPC element
264
"""
265
266
def wrap_rpc_reply(data):
267
"""
268
Wrap data in NETCONF RPC reply envelope.
269
270
Parameters:
271
- data: Element, reply data content
272
273
Returns:
274
Element: NETCONF rpc-reply element
275
"""
276
```
277
278
## Usage Examples
279
280
### Creating XML Elements
281
282
```python
283
from ncclient.xml_ import new_ele, sub_ele, to_xml
284
285
# Create root element
286
config = new_ele("config")
287
288
# Add sub-elements
289
interface = sub_ele(config, "interface")
290
sub_ele(interface, "name").text = "eth0"
291
sub_ele(interface, "description").text = "Management Interface"
292
293
# Convert to XML string
294
xml_string = to_xml(config, pretty_print=True)
295
print(xml_string)
296
```
297
298
### Working with Namespaces
299
300
```python
301
from ncclient.xml_ import new_ele_ns, sub_ele_ns, BASE_NS_1_0
302
303
# Create namespaced elements
304
rpc = new_ele_ns("rpc", BASE_NS_1_0, {"message-id": "101"})
305
get_config = sub_ele_ns(rpc, "get-config", BASE_NS_1_0)
306
source = sub_ele_ns(get_config, "source", BASE_NS_1_0)
307
sub_ele_ns(source, "running", BASE_NS_1_0)
308
309
print(to_xml(rpc, pretty_print=True))
310
```
311
312
### Parsing XML Documents
313
314
```python
315
from ncclient.xml_ import parse_root, to_ele
316
317
# Parse XML from string
318
xml_data = '''
319
<rpc-reply xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
320
<data>
321
<interfaces>
322
<interface>
323
<name>eth0</name>
324
<type>ethernet</type>
325
</interface>
326
</interfaces>
327
</data>
328
</rpc-reply>
329
'''
330
331
# Parse and extract data
332
root = parse_root(xml_data)
333
data = root.find(".//{urn:ietf:params:xml:ns:netconf:base:1.0}data")
334
335
# Work with parsed elements
336
interfaces = data.find(".//interfaces")
337
for interface in interfaces.findall(".//interface"):
338
name = interface.find("name").text
339
iface_type = interface.find("type").text
340
print(f"Interface: {name}, Type: {iface_type}")
341
```
342
343
### Building NETCONF Filters
344
345
```python
346
from ncclient.xml_ import build_filter, new_ele, sub_ele
347
348
# Subtree filter
349
filter_spec = '''
350
<interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces">
351
<interface>
352
<name/>
353
<type/>
354
<admin-status/>
355
</interface>
356
</interfaces>
357
'''
358
359
# Build filter element
360
filter_elem = build_filter(filter_spec, "subtree")
361
362
# XPath filter
363
xpath_filter = "/interfaces/interface[name='eth0']"
364
xpath_elem = build_filter(xpath_filter, "xpath")
365
```
366
367
### Custom XML Processing
368
369
```python
370
from ncclient.xml_ import parse_root, new_ele, sub_ele, to_xml
371
372
def extract_interface_config(config_xml):
373
"""Extract interface configuration from NETCONF data."""
374
root = parse_root(config_xml)
375
interfaces = []
376
377
# Find all interface elements
378
for interface in root.findall(".//interface"):
379
interface_data = {
380
'name': interface.find("name").text if interface.find("name") is not None else None,
381
'description': interface.find("description").text if interface.find("description") is not None else None,
382
'admin_status': interface.find("admin-status").text if interface.find("admin-status") is not None else None
383
}
384
interfaces.append(interface_data)
385
386
return interfaces
387
388
def build_interface_config(interface_data):
389
"""Build interface configuration XML."""
390
config = new_ele("config")
391
interfaces = sub_ele(config, "interfaces")
392
393
for iface in interface_data:
394
interface = sub_ele(interfaces, "interface")
395
sub_ele(interface, "name").text = iface['name']
396
if iface.get('description'):
397
sub_ele(interface, "description").text = iface['description']
398
if iface.get('admin_status'):
399
sub_ele(interface, "admin-status").text = iface['admin_status']
400
401
return to_xml(config, pretty_print=True)
402
403
# Usage
404
config_data = [
405
{'name': 'eth0', 'description': 'Management', 'admin_status': 'up'},
406
{'name': 'eth1', 'description': 'Data', 'admin_status': 'up'}
407
]
408
409
xml_config = build_interface_config(config_data)
410
print(xml_config)
411
```
412
413
### Error Handling
414
415
```python
416
from ncclient.xml_ import parse_root, XMLError
417
418
def safe_parse_xml(xml_string):
419
"""Safely parse XML with error handling."""
420
try:
421
root = parse_root(xml_string)
422
return root
423
except XMLError as e:
424
print(f"XML parsing error: {e}")
425
return None
426
except Exception as e:
427
print(f"Unexpected error: {e}")
428
return None
429
430
# Parse potentially malformed XML
431
malformed_xml = "<config><interface><name>eth0</interface></config>" # Missing closing tag
432
result = safe_parse_xml(malformed_xml)
433
if result is None:
434
print("Failed to parse XML")
435
```
436
437
### Working with Large XML Documents
438
439
```python
440
from ncclient.xml_ import _get_parser, etree
441
442
def parse_large_xml(xml_data):
443
"""Parse large XML documents with huge tree support."""
444
parser = _get_parser(huge_tree=True)
445
446
try:
447
root = etree.fromstring(xml_data, parser)
448
return root
449
except etree.XMLSyntaxError as e:
450
print(f"XML syntax error: {e}")
451
return None
452
453
# Process large configuration files
454
large_xml_data = open('large_config.xml', 'rb').read()
455
root = parse_large_xml(large_xml_data)
456
if root is not None:
457
print(f"Parsed large XML with {len(root)} child elements")
458
```