commit 395df7295792b222e0d4a6d53c2ef323702f5197
Author: Radek Pazdera <rpazdera(a)redhat.com>
Date: Tue Aug 6 13:40:54 2013 +0200
XmlProcessing: Split into two separate modules
I added a few new classes to the XmlProcessing file and split it into
two separate modules XmlProcessing and XmlParser.
The XmlProcessing module now contains only the basic classes and the
parser bases were moved to the new module.
New classes:
class XmlData - a structure representing XML data
class XmlCollection - an array (collection) of XmlData structures
Signed-off-by: Radek Pazdera <rpazdera(a)redhat.com>
Signed-off-by: Jiri Pirko <jiri(a)resnulli.us>
lnst/Common/XmlParser.py | 271 +++++++++++++++++++++++
lnst/Common/XmlProcessing.py | 399 +++++++++++-----------------------
lnst/Common/XmlTemplates.py | 1 +
lnst/Controller/RecipeParse.py | 6 +-
lnst/Controller/SlaveMachineParse.py | 6 +-
lnst/Controller/SlavePool.py | 3 +-
6 files changed, 408 insertions(+), 278 deletions(-)
---
diff --git a/lnst/Common/XmlParser.py b/lnst/Common/XmlParser.py
new file mode 100644
index 0000000..69e21e5
--- /dev/null
+++ b/lnst/Common/XmlParser.py
@@ -0,0 +1,271 @@
+"""
+This module contains the XmlParser and LnstParser classes.
+
+Copyright 2013 Red Hat, Inc.
+Licensed under the GNU General Public License, version 2 as
+published by the Free Software Foundation; see COPYING for details.
+"""
+
+__author__ = """
+rpazdera(a)redhat.com (Radek Pazdera)
+"""
+
+import os
+import logging
+from xml.dom.minidom import parseString
+from xml import sax
+from lnst.Common.XmlTemplates import XmlTemplates, XmlTemplateError
+from lnst.Common.RecipePath import RecipePath
+from lnst.Common.XmlProcessing import XmlProcessingError, XmlDomTreeInit
+from lnst.Common.XmlProcessing import XmlData
+
+class XmlParser(object):
+ """ Parent class for XML processors
+
+ This class handles manipulation of XML DOM objects
+ that are used for processing XML files.
+
+ The standard DOM objects are extended with position data
+ (file name, line number and column number) that can be
+ used in error reporting.
+ """
+
+ def _process_child_nodes(self, parent, scheme, params=None,
+ default_handler=None):
+ child_nodes = parent.childNodes
+
+ if not params:
+ params = {}
+
+ for node in child_nodes:
+ if node.nodeType == node.COMMENT_NODE or \
+ node.nodeType == node.TEXT_NODE:
+ continue
+ elif node.nodeType == node.ELEMENT_NODE:
+ node_name = node.nodeName
+ if node_name in scheme:
+ handler = scheme[node_name]
+ self._process_node(node, handler, params)
+ elif default_handler:
+ self._process_node(node, default_handler, params)
+ else:
+ msg = "Unexpected '%s' tag under '%s'" %
(node_name,
+ parent.nodeName)
+ raise XmlProcessingError(msg, node)
+ else:
+ msg = "Only XML elements are allowed here!"
+ raise XmlProcessingError(msg, node)
+
+ def _process_node(self, node, handler, params):
+ handler(node, params)
+
+ @staticmethod
+ def _convert_string(node, string, conversion_cb):
+ if conversion_cb:
+ try:
+ converted = conversion_cb(string)
+ except ValueError as err:
+ raise XmlProcessingError("Conversion error: " + str(err),
node)
+ return converted
+
+ return string
+
+ def _has_attribute(self, node, attr_name):
+ return node.hasAttribute(attr_name)
+
+ def _get_attribute(self, node, attr_name, conversion_cb=None):
+ if not self._has_attribute(node, attr_name):
+ msg = "Expected attribute '%s' missing" % attr_name
+ raise XmlProcessingError(msg, node)
+ attr_val = str(node.getAttribute(attr_name))
+ return self._convert_string(node, attr_val, conversion_cb)
+
+ def _get_text_content(self, node, conversion_cb=None):
+ content = []
+ for child in node.childNodes:
+ if child.nodeType == child.TEXT_NODE:
+ content.append(child.nodeValue)
+
+ text = str(''.join(content).strip())
+ return self._convert_string(node, text, conversion_cb)
+
+ def _get_all_attributes(self, node):
+ res = {}
+ for i in range(0, node.attributes.length):
+ attr = node.attributes.item(i)
+ res[attr.name] = attr.value
+
+ return res
+
+class LnstParser(XmlParser):
+ """ Enhanced XmlParser
+
+ This class enhances XmlParser with advanced features that are
+ used in parsing LNST XML files. All (sub)parsers should
+ use this as their base class.
+ """
+
+ _data = None
+ _template_proc = None
+ _include_root = None
+ _events_enabled = None
+ _event_handlers = None
+
+ def __init__(self, parent=None):
+ super(LnstParser, self).__init__()
+
+ if parent:
+ self._data = parent._data
+ self._template_proc = parent._template_proc
+ self._include_root = parent._include_root
+ self._events_enabled = parent._events_enabled
+ self._event_handlers = parent._event_handlers
+ else:
+ self._data = None
+ self._template_proc = XmlTemplates()
+ self._include_root = os.getcwd()
+ self._events_enabled = True
+ self._event_handlers = {}
+
+ def set_target(self, data_dict):
+ self._data = data_dict
+
+ def get_data(self):
+ return self._data
+
+ def set_machines(self, machines):
+ self._template_proc.set_machines(machines)
+
+ def set_definitions(self, defs):
+ self._template_proc.set_definitions(defs)
+
+ def set_include_root(self, include_root_path):
+ self._include_root = include_root_path
+
+ def enable_events(self):
+ self._events_enabled = True
+
+ def disable_events(self):
+ self._events_enabled = False
+
+ def register_event_handler(self, event_id, handler):
+ self._event_handlers[event_id] = handler
+
+ def _trigger_event(self, event_id, args):
+ if not self._events_enabled:
+ return
+
+ try:
+ handler = self._event_handlers[event_id]
+ except KeyError as err:
+ logging.warn("No handler found for %s event, ignoring", event_id)
+ return
+
+ handler(**args)
+
+ def _process_child_nodes(self, node, scheme, params=None,
+ default_handler=None, new_ns_level=True):
+ scheme["define"] = self._define_handler
+
+ if not params:
+ params = {}
+
+ if new_ns_level:
+ self._template_proc.add_namespace_level()
+
+ parent = super(LnstParser, self)
+ result = parent._process_child_nodes(node, scheme, params,
+ default_handler)
+
+ if new_ns_level:
+ self._template_proc.drop_namespace_level()
+
+ return result
+
+ def _process_node(self, node, handler, params):
+ old_include_root = None
+ if self._has_attribute(node, "source"):
+ source = self._get_attribute(node, "source")
+
+ source_rp = RecipePath(self._include_root, source)
+
+ old_include_root = self._include_root
+ self._include_root = source_rp.get_root()
+ xmlstr = source_rp.to_str()
+
+ dom_init = XmlDomTreeInit()
+ try:
+ dom = dom_init.parse_string(xmlstr,
+ filename=source_rp.abs_path())
+ except IOError as err:
+ msg = "Unable to resolve include: %s" % str(err)
+ raise XmlProcessingError(msg, node)
+
+ loaded_node = None
+ try:
+ loaded_node = dom.getElementsByTagName(node.nodeName)[0]
+ except Exception:
+ msg = ("No '%s' element present in included file
'%s'."
+ % (node.nodeName, source_rp.abs_path()))
+ raise XmlProcessingError(msg, node)
+
+ old_attrs = self._get_all_attributes(node)
+
+ parent = node.parentNode
+ parent.replaceChild(loaded_node, node)
+ node = loaded_node
+
+ # copy all of the original attributes to the sourced node
+ for name, value in old_attrs.iteritems():
+ # do not overwrite sourced attributes
+ if not node.hasAttribute(name):
+ node.setAttribute(name, value)
+
+ parent = super(LnstParser, self)
+ parent._process_node(node, handler, params)
+
+ if old_include_root:
+ self._include_root = old_include_root
+
+ def _get_attribute(self, node, attr_name, conversion_cb=None):
+ parent = super(LnstParser, self)
+ raw_attr_val = parent._get_attribute(node, attr_name)
+
+ try:
+ attr_val = self._template_proc.expand_string(raw_attr_val, node)
+ except XmlTemplateError as err:
+ raise XmlProcessingError(str(err), node)
+
+ return self._convert_string(node, attr_val, conversion_cb)
+
+ def _get_text_content(self, node, conversion_cb=None):
+ parent = super(LnstParser, self)
+ raw_content = parent._get_text_content(node)
+
+ try:
+ content = self._template_proc.expand_string(raw_content, node)
+ except XmlTemplateError as err:
+ raise XmlProcessingError(str(err), node)
+
+ return self._convert_string(node, content, conversion_cb)
+
+ def _define_handler(self, node, params):
+ scheme = {"alias": self._alias_handler}
+ self._process_child_nodes(node, scheme, new_ns_level=False)
+
+ def _alias_handler(self, node, params):
+ if self._has_attribute(node, "name"):
+ name = self._get_attribute(node, "name")
+ else:
+ msg = "Alias tag must have the 'name' attribute"
+ raise XmlProcessingError(msg, node)
+
+ if self._has_attribute(node, "value"):
+ value = self._get_attribute(node, "value")
+ else:
+ value = self._get_text_content(node)
+
+ try:
+ self._template_proc.define_alias(name, value)
+ except XmlTemplateError as err:
+ raise XmlProcessingError(str(err), node)
diff --git a/lnst/Common/XmlProcessing.py b/lnst/Common/XmlProcessing.py
index 8e28915..a709659 100644
--- a/lnst/Common/XmlProcessing.py
+++ b/lnst/Common/XmlProcessing.py
@@ -14,9 +14,6 @@ import os
import logging
from xml.dom.minidom import parseString
from xml import sax
-from lnst.Common.XmlTemplates import XmlTemplates, XmlTemplateError
-from lnst.Common.RecipePath import RecipePath
-
class XmlProcessingError(Exception):
""" Exception thrown on parsing errors """
@@ -25,26 +22,26 @@ class XmlProcessingError(Exception):
_line = None
_col = None
- def __init__(self, msg, node=None):
+ def __init__(self, msg, obj=None):
super(XmlProcessingError, self).__init__()
self._msg = msg
- if node and hasattr(node, "parse_position"):
- self.set_pos(node.parse_position)
+ if obj and hasattr(obj, "loc"):
+ self.set_loc(obj.loc)
#logging.error(self.__str__())
- def set_pos(self, pos):
- self._filename = pos["file"]
- self._line = pos["line"]
- #self._col = pos["col"]
+ def set_loc(self, loc):
+ self._filename = loc["file"]
+ self._line = loc["line"]
+ #self._col = loc["col"]
def __str__(self):
line = ""
col = ""
sep = ""
- pos = ""
+ loc = ""
filename = "<unknown>"
if self._filename:
@@ -58,18 +55,127 @@ class XmlProcessingError(Exception):
col = "%s%d" % (sep, self._col)
if self._line or self._col:
- pos = "%s%s:" % (line, col)
+ loc = "%s%s:" % (line, col)
+
+ return "%s:%s %s" % (filename, loc, self._msg)
+
+class XmlDataIterator:
+ def __init__(self, iterator):
+ self._iterator = iterator
+
+ def __iter__(self):
+ return self
+
+ def next(self):
+ n = self._iterator.next()
+
+ # For normal iterators
+ if type(n) == XmlTemplateString:
+ return str(n)
+
+ # For iteritems() iterators
+ if type(n) == tuple and len(n) == 2 and type(n[1]) == XmlTemplateString:
+ return (n[0], str(n[1]))
+
+ return n
+
+class XmlCollection(list):
+ def __init__(self, node=None):
+ super(XmlCollection, self).__init__()
+ if node:
+ self.loc = node.loc
+
+ def __getitem__(self, key):
+ value = super(XmlCollection, self).__getitem__(key)
+ if type(value) == XmlData or type(value) == XmlCollection:
+ return value
+
+ return str(value)
+
+ def __iter__(self):
+ it = super(XmlCollection, self).__iter__()
+ return XmlDataIterator(it)
- return "XmlProcessingError:%s:%s %s" % (filename, pos, self._msg)
+class XmlData(dict):
+ def __init__(self, node=None):
+ super(XmlData, self).__init__()
+ if node:
+ self.loc = node.loc
+
+ def __getitem__(self, key):
+ value = super(XmlData, self).__getitem__(key)
+ if type(value) == XmlData or type(value) == XmlCollection:
+ return value
+
+ return str(value)
+
+ def __iter__(self):
+ it = super(XmlData, self).__iter__()
+ return XmlDataIterator(it)
+
+ def iteritems(self):
+ it = super(XmlData, self).iteritems()
+ return XmlDataIterator(it)
+
+ def iterkeys(self):
+ it = super(XmlData, self).iterkeys()
+ return XmlDataIterator(it)
+
+ def itervalues(self):
+ it = super(XmlData, self).itervalues()
+ return XmlDataIterator(it)
+
+class XmlTemplateString(object):
+ def __init__(self, param=None, node=None):
+ if type(param) == str:
+ self._parts = [param]
+ elif type(param) == list:
+ self._parts = param
+ else:
+ self._parts = []
+
+ if node and hasattr(node, "loc"):
+ self.loc = node.loc
+
+ def __add__(self, other):
+ if type(other) is str:
+ self.add_part(other)
+ elif type(other) is self.__class__:
+ self._parts += other._parts
+ else:
+ raise XmlProcessingError("Cannot concatenate %s and %s" % \
+ str(type(self)), str(type(other)))
+ return self
+
+ def __str__(self):
+ string = ""
+ for part in self._parts:
+ string += str(part)
+ return string
+
+ def __hash__(self):
+ return hash(str(self))
+
+ def __eq__(self, other):
+ return str(self) == str(other)
+
+ def __ne__(self, other):
+ return str(self) != str(other)
+
+ def __len__(self):
+ return len(str(self))
+
+ def add_part(self, part):
+ self._parts.append(part)
class XmlDomTreeInit:
""" Handles creation/initialization of DOM trees
It allows you to parse XML file or string into a DOM tree.
It also adds an extra parameter to each node of the tree
- called `parse_position' which can be used to determine
- where exactly was the element placed in the original source
- XML file. This is useful for error reporting.
+ called `loc' which can be used to determine where exactly
+ was the element placed in the original source XML file.
+ This is useful for error reporting.
"""
_sax = None
@@ -89,10 +195,10 @@ class XmlDomTreeInit:
def start_element_ns(name, tag_name , attrs):
orig_start_cb(name, tag_name, attrs)
cur_elem = dom_handler.elementStack[-1]
- pos = {"file": self._filename,
+ loc = {"file": self._filename,
"line": self._sax.getLineNumber(),
"col": self._sax.getColumnNumber()}
- cur_elem.parse_position = pos
+ cur_elem.loc = loc
orig_start_cb = dom_handler.startElementNS
dom_handler.startElementNS = start_element_ns
@@ -115,262 +221,13 @@ class XmlDomTreeInit:
try:
dom = parseString(xml_text, self._sax)
except sax.SAXParseException as err:
- pos = {"file": self._filename,
+ loc = {"file": self._filename,
"line": err.getLineNumber(),
"col": err.getColumnNumber()}
exc = XmlProcessingError(err.getMessage())
- exc.set_pos(pos)
+ exc.set_loc(loc)
raise exc
- pos = {"file": self._filename, "line": 0, "col":
0}
- dom.parse_position = pos
+ loc = {"file": self._filename, "line": 0, "col":
0}
+ dom.loc = loc
return dom
-
-
-class XmlParser(object):
- """ Parent class for XML processors
-
- This class handles manipulation of XML DOM objects
- that are used for processing XML files.
-
- The standard DOM objects are extended with position data
- (file name, line number and column number) that can be
- used in error reporting.
- """
-
- def _process_child_nodes(self, parent, scheme, params=None,
- default_handler=None):
- child_nodes = parent.childNodes
-
- if not params:
- params = {}
-
- for node in child_nodes:
- if node.nodeType == node.COMMENT_NODE or \
- node.nodeType == node.TEXT_NODE:
- continue
- elif node.nodeType == node.ELEMENT_NODE:
- node_name = node.nodeName
- if node_name in scheme:
- handler = scheme[node_name]
- self._process_node(node, handler, params)
- elif default_handler:
- self._process_node(node, default_handler, params)
- else:
- msg = "Unexpected '%s' tag under '%s'" %
(node_name,
- parent.nodeName)
- raise XmlProcessingError(msg, node)
- else:
- msg = "Only XML elements are allowed here!"
- raise XmlProcessingError(msg, node)
-
- def _process_node(self, node, handler, params):
- handler(node, params)
-
- @staticmethod
- def _convert_string(node, string, conversion_cb):
- if conversion_cb:
- try:
- converted = conversion_cb(string)
- except ValueError as err:
- raise XmlProcessingError("Conversion error: " + str(err),
node)
- return converted
-
- return string
-
- def _has_attribute(self, node, attr_name):
- return node.hasAttribute(attr_name)
-
- def _get_attribute(self, node, attr_name, conversion_cb=None):
- if not self._has_attribute(node, attr_name):
- msg = "Expected attribute '%s' missing" % attr_name
- raise XmlProcessingError(msg, node)
- attr_val = str(node.getAttribute(attr_name))
- return self._convert_string(node, attr_val, conversion_cb)
-
- def _get_text_content(self, node, conversion_cb=None):
- content = []
- for child in node.childNodes:
- if child.nodeType == child.TEXT_NODE:
- content.append(child.nodeValue)
-
- text = str(''.join(content).strip())
- return self._convert_string(node, text, conversion_cb)
-
- def _get_all_attributes(self, node):
- res = {}
- for i in range(0, node.attributes.length):
- attr = node.attributes.item(i)
- res[attr.name] = attr.value
-
- return res
-
-class LnstParser(XmlParser):
- """ Enhanced XmlParser
-
- This class enhances XmlParser with advanced features that are
- used in parsing LNST XML files. All (sub)parsers should
- use this as their base class.
- """
-
- _data = None
- _template_proc = None
- _include_root = None
- _events_enabled = None
- _event_handlers = None
-
- def __init__(self, parent=None):
- super(LnstParser, self).__init__()
-
- if parent:
- self._data = parent._data
- self._template_proc = parent._template_proc
- self._include_root = parent._include_root
- self._events_enabled = parent._events_enabled
- self._event_handlers = parent._event_handlers
- else:
- self._data = {}
- self._template_proc = XmlTemplates()
- self._include_root = os.getcwd()
- self._events_enabled = True
- self._event_handlers = {}
-
- def set_target(self, data_dict):
- self._data = data_dict
-
- def set_machines(self, machines):
- self._template_proc.set_machines(machines)
-
- def set_definitions(self, defs):
- self._template_proc.set_definitions(defs)
-
- def set_include_root(self, include_root_path):
- self._include_root = include_root_path
-
- def enable_events(self):
- self._events_enabled = True
-
- def disable_events(self):
- self._events_enabled = False
-
- def register_event_handler(self, event_id, handler):
- self._event_handlers[event_id] = handler
-
- def _trigger_event(self, event_id, args):
- if not self._events_enabled:
- return
-
- try:
- handler = self._event_handlers[event_id]
- except KeyError as err:
- logging.warn("No handler found for %s event, ignoring", event_id)
- return
-
- handler(**args)
-
- def _process_child_nodes(self, node, scheme, params=None,
- default_handler=None, new_ns_level=True):
- scheme["define"] = self._define_handler
-
- if not params:
- params = {}
-
- if new_ns_level:
- self._template_proc.add_namespace_level()
-
- parent = super(LnstParser, self)
- result = parent._process_child_nodes(node, scheme, params,
- default_handler)
-
- if new_ns_level:
- self._template_proc.drop_namespace_level()
-
- return result
-
- def _process_node(self, node, handler, params):
- old_include_root = None
- if self._has_attribute(node, "source"):
- source = self._get_attribute(node, "source")
-
- source_rp = RecipePath(self._include_root, source)
-
- old_include_root = self._include_root
- self._include_root = source_rp.get_root()
- xmlstr = source_rp.to_str()
-
- dom_init = XmlDomTreeInit()
- try:
- dom = dom_init.parse_string(xmlstr,
- filename=source_rp.abs_path())
- except IOError as err:
- msg = "Unable to resolve include: %s" % str(err)
- raise XmlProcessingError(msg, node)
-
- loaded_node = None
- try:
- loaded_node = dom.getElementsByTagName(node.nodeName)[0]
- except Exception:
- msg = ("No '%s' element present in included file
'%s'."
- % (node.nodeName, source_rp.abs_path()))
- raise XmlProcessingError(msg, node)
-
- old_attrs = self._get_all_attributes(node)
-
- parent = node.parentNode
- parent.replaceChild(loaded_node, node)
- node = loaded_node
-
- # copy all of the original attributes to the sourced node
- for name, value in old_attrs.iteritems():
- # do not overwrite sourced attributes
- if not node.hasAttribute(name):
- node.setAttribute(name, value)
-
- parent = super(LnstParser, self)
- parent._process_node(node, handler, params)
-
- if old_include_root:
- self._include_root = old_include_root
-
- def _get_attribute(self, node, attr_name, conversion_cb=None):
- parent = super(LnstParser, self)
- raw_attr_val = parent._get_attribute(node, attr_name)
-
- try:
- attr_val = self._template_proc.expand_string(raw_attr_val)
- except XmlTemplateError as err:
- raise XmlProcessingError(str(err), node)
-
- return self._convert_string(node, attr_val, conversion_cb)
-
- def _get_text_content(self, node, conversion_cb=None):
- parent = super(LnstParser, self)
- raw_content = parent._get_text_content(node)
-
- try:
- content = self._template_proc.expand_string(raw_content)
- except XmlTemplateError as err:
- raise XmlProcessingError(str(err), node)
-
- return self._convert_string(node, content, conversion_cb)
-
- def _define_handler(self, node, params):
- scheme = {"alias": self._alias_handler}
- self._process_child_nodes(node, scheme, new_ns_level=False)
-
- def _alias_handler(self, node, params):
- if self._has_attribute(node, "name"):
- name = self._get_attribute(node, "name")
- else:
- msg = "Alias tag must have the 'name' attribute"
- raise XmlProcessingError(msg, node)
-
- if self._has_attribute(node, "value"):
- value = self._get_attribute(node, "value")
- else:
- value = self._get_text_content(node)
-
- try:
- self._template_proc.define_alias(name, value)
- except XmlTemplateError as err:
- raise XmlProcessingError(str(err), node)
diff --git a/lnst/Common/XmlTemplates.py b/lnst/Common/XmlTemplates.py
index 28a6d51..ed50e83 100644
--- a/lnst/Common/XmlTemplates.py
+++ b/lnst/Common/XmlTemplates.py
@@ -22,6 +22,7 @@ rpazdera(a)redhat.com (Radek Pazdera)
"""
import re
+from lnst.Common.XmlProcessing import XmlTemplateString
class XmlTemplateError(Exception):
pass
diff --git a/lnst/Controller/RecipeParse.py b/lnst/Controller/RecipeParse.py
index 04cb648..311243d 100644
--- a/lnst/Controller/RecipeParse.py
+++ b/lnst/Controller/RecipeParse.py
@@ -13,12 +13,12 @@ jpirko(a)redhat.com (Jiri Pirko)
import logging
import os
import re
-from lnst.Common.XmlProcessing import LnstParser
-from lnst.Common.XmlProcessing import XmlDomTreeInit
-from lnst.Common.XmlProcessing import XmlProcessingError
from lnst.Common.NetUtils import normalize_hwaddr
from lnst.Common.Utils import bool_it
from lnst.Common.RecipePath import RecipePath
+from lnst.Common.XmlProcessing import XmlDomTreeInit, XmlData
+from lnst.Common.XmlProcessing import XmlProcessingError
+from lnst.Common.XmlParser import LnstParser
class RecipeParse(LnstParser):
def __init__(self, recipe_filepath):
diff --git a/lnst/Controller/SlaveMachineParse.py b/lnst/Controller/SlaveMachineParse.py
index 4be2dc5..08f84e0 100644
--- a/lnst/Controller/SlaveMachineParse.py
+++ b/lnst/Controller/SlaveMachineParse.py
@@ -14,11 +14,11 @@ rpazdera(a)redhat.com (Radek Pazdera)
import logging
import os
import re
-from lnst.Common.XmlProcessing import LnstParser
-from lnst.Common.XmlProcessing import XmlDomTreeInit
-from lnst.Common.XmlProcessing import XmlProcessingError
from lnst.Common.NetUtils import normalize_hwaddr
from lnst.Controller.RecipeParse import ParamsParse
+from lnst.Common.XmlParser import LnstParser
+from lnst.Common.XmlProcessing import XmlDomTreeInit
+from lnst.Common.XmlProcessing import XmlProcessingError, XmlData
class SlaveMachineParse(LnstParser):
_machine_id = None
diff --git a/lnst/Controller/SlavePool.py b/lnst/Controller/SlavePool.py
index 05c6041..db59ed4 100644
--- a/lnst/Controller/SlavePool.py
+++ b/lnst/Controller/SlavePool.py
@@ -18,9 +18,10 @@ import os
import re
import copy
from xml.dom import minidom
-from lnst.Common.XmlProcessing import XmlDomTreeInit
from lnst.Common.NetUtils import test_tcp_connection
from lnst.Controller.SlaveMachineParse import SlaveMachineParse
+from lnst.Common.XmlProcessing import XmlDomTreeInit
+from lnst.Common.XmlProcessing import XmlProcessingError, XmlData
from lnst.Controller.Machine import Machine
from lnst.Common.Config import lnst_config