21 from lxml
import etree
as lxml_etree
28 from collections.abc
import MutableMapping
29 Attrib = getattr(lxml_etree,
'_Attrib',
None)
30 if Attrib
and not isinstance(Attrib, MutableMapping):
31 MutableMapping.register(Attrib)
32 del Attrib, MutableMapping
37 from robot.utils import (asserts, ET, ETSource, is_bytes, is_falsy, is_string,
38 is_truthy, plural_or_not
as s)
42 should_be_equal = asserts.assert_equal
457 ROBOT_LIBRARY_SCOPE =
'GLOBAL'
462 _xml_declaration = re.compile(
'^<\?xml .*\?>')
478 if use_lxml
and lxml_etree:
486 if use_lxml
and not lxml_etree:
487 logger.warn(
'XML library reverted to use standard ElementTree '
488 'because lxml module is not installed.')
521 def parse_xml(self, source, keep_clark_notation=False, strip_namespaces=False):
522 if isinstance(source, os.PathLike):
524 with ETSource(source)
as source:
525 tree = self.
etreeetree.parse(source)
527 strip = (lxml_etree.Comment, lxml_etree.ProcessingInstruction)
528 lxml_etree.strip_elements(tree, *strip, **dict(with_tail=
False))
529 root = tree.getroot()
561 if len(elements) != 1:
572 return "No element matching '%s' found." % xpath
574 return "One element matching '%s' found." % xpath
575 return "Multiple elements (%d) matching '%s' found." % (count, xpath)
594 if isinstance(source, (str, bytes, os.PathLike)):
597 return finder.find_all(source, xpath)
615 return list(self.
get_elementget_element(source, xpath))
625 count = len(self.
get_elementsget_elements(source, xpath))
626 logger.info(
"%d element%s matched '%s'." % (count, s(count), xpath))
690 element = self.
get_elementget_element(source, xpath)
699 for child
in element:
700 for text
in self.
_yield_texts_yield_texts(child, top=
False):
702 if element.tail
and not top:
706 return ' '.join(text.split())
725 return [self.
get_element_textget_element_text(elem, normalize_whitespace=normalize_whitespace)
726 for elem
in self.
get_elementsget_elements(source, xpath)]
751 normalize_whitespace=False, message=None):
752 text = self.
get_element_textget_element_text(source, xpath, normalize_whitespace)
771 normalize_whitespace=False, message=None):
772 text = self.
get_element_textget_element_text(source, xpath, normalize_whitespace)
796 return self.
get_elementget_element(source, xpath).get(name, default)
816 return dict(self.
get_elementget_element(source, xpath).attrib)
884 "has value '%s'." % (name, attr))
922 normalize_whitespace=False):
924 exclude_children, normalize_whitespace)
943 normalize_whitespace=False):
945 exclude_children, normalize_whitespace)
948 normalize_whitespace):
950 if is_truthy(normalize_whitespace)
else None
973 self.
get_elementget_element(source, xpath).tag = tag
983 for elem
in self.
get_elementsget_elements(source, xpath):
1012 element = self.
get_elementget_element(source, xpath)
1013 if text
is not None:
1015 if tail
is not None:
1019 @keyword(types=None)
1027 for elem
in self.
get_elementsget_elements(source, xpath):
1055 self.
get_elementget_element(source, xpath).attrib[name] = value
1065 for elem
in self.
get_elementsget_elements(source, xpath):
1089 attrib = self.
get_elementget_element(source, xpath).attrib
1101 for elem
in self.
get_elementsget_elements(source, xpath):
1124 self.
get_elementget_element(source, xpath).attrib.clear()
1134 for elem
in self.
get_elementsget_elements(source, xpath):
1166 parent = self.
get_elementget_element(source, xpath)
1169 parent.append(element)
1171 parent.insert(int(index), element)
1220 for element
in self.
get_elementsget_elements(source, xpath):
1228 parent.remove(element)
1231 for parent
in root.iter():
1232 for child
in parent:
1233 if child
is element:
1238 if not element.tail:
1240 index = list(parent).index(element)
1242 parent.text = (parent.text
or '') + element.tail
1244 sibling = parent[index-1]
1245 sibling.tail = (sibling.tail
or '') + element.tail
1273 element = self.
get_elementget_element(source, xpath)
1299 return copy.deepcopy(self.
get_elementget_element(source, xpath))
1314 source = self.
get_elementget_element(source, xpath)
1315 string = self.
etreeetree.tostring(source, encoding=
'UTF-8').decode(
'UTF-8')
1318 string = string.encode(encoding)
1331 logger.write(string, level)
1354 path = os.path.abspath(str(path)
if isinstance(path, os.PathLike)
1355 else path.replace(
'/', os.sep))
1357 tree = self.
etreeetree.ElementTree(elem)
1358 config = {
'encoding': encoding}
1360 config[
'xml_declaration'] =
True
1364 if tree.docinfo.doctype:
1365 config[
'doctype'] = tree.docinfo.doctype
1366 tree = self.
etreeetree.ElementTree(elem)
1367 with open(path,
'wb')
as output:
1368 if 'doctype' in config:
1369 output.write(self.
etreeetree.tostring(tree, **config))
1371 tree.write(output, **config)
1372 logger.info(
'XML saved to <a href="file://%s">%s</a>.' % (path, path),
1398 raise RuntimeError(
"'Evaluate Xpath' keyword only works in lxml mode.")
1399 return self.
get_elementget_element(source, context).xpath(expression)
1408 def strip(self, elem, preserve=True, current_ns=None, top=True):
1409 if elem.tag.startswith(
'{')
and '}' in elem.tag:
1410 ns, elem.tag = elem.tag[1:].split(
'}', 1)
1411 if preserve
and ns != current_ns:
1412 elem.attrib[
'xmlns'] = ns
1415 elem.attrib[
'xmlns'] =
''
1418 self.
stripstrip(child, preserve, current_ns, top=
False)
1419 if top
and not preserve
and self.
lxml_treelxml_tree:
1420 self.
etreeetree.cleanup_namespaces(elem)
1422 def unstrip(self, elem, current_ns=None, copied=False):
1424 elem = copy.deepcopy(elem)
1425 ns = elem.attrib.pop(
'xmlns', current_ns)
1427 elem.tag =
'{%s}%s' % (ns, elem.tag)
1429 self.
unstripunstrip(child, ns, copied=
True)
1444 if not self.
lxmllxml:
1445 return elem.findall(xpath)
1446 finder = self.
etreeetree.ETXPath(xpath)
1456 except UnicodeError:
1457 if not xpath.replace(
'/',
'').isalnum():
1458 logger.warn(
'XPATHs containing non-ASCII characters and '
1459 'other than tag names do not always work with '
1460 'Python versions prior to 2.7. Verify results '
1461 'manually and consider upgrading to 2.7.')
1467 def __init__(self, comparator, normalizer=None, exclude_children=False):
1472 def compare(self, actual, expected, location=None):
1478 if location.is_not_root:
1484 self.
_compare_compare(actual.tag, expected.tag,
'Different tag name', location,
1487 def _compare(self, actual, expected, message, location, comparator=None):
1488 if location.is_not_root:
1489 message =
"%s at '%s'" % (message, location.path)
1492 comparator(actual, expected, message)
1495 self.
_compare_compare(sorted(actual.attrib), sorted(expected.attrib),
1496 'Different attribute names', location, should_be_equal)
1497 for key
in actual.attrib:
1498 self.
_compare_compare(actual.attrib[key], expected.attrib[key],
1499 "Different value for attribute '%s'" % key, location)
1503 'Different text', location)
1510 'Different tail text', location)
1513 self.
_compare_compare(len(actual), len(expected),
'Different number of child elements',
1514 location, should_be_equal)
1515 for act, exp
in zip(actual, expected):
1516 self.
comparecompare(act, exp, location.child(act.tag))
1531 tag +=
'[%d]' % self.
_children_children[tag]
1532 return Location(
'%s/%s' % (self.
pathpath, tag), is_root=
False)
An always available standard library with often needed keywords.
def _compare(self, actual, expected, message, location, comparator=None)
def _compare_attributes(self, actual, expected, location)
def _compare_texts(self, actual, expected, location)
def _compare_children(self, actual, expected, location)
def compare(self, actual, expected, location=None)
def _compare_tails(self, actual, expected, location)
def _compare_tags(self, actual, expected, location)
def __init__(self, comparator, normalizer=None, exclude_children=False)
def _get_xpath(self, xpath)
def find_all(self, elem, xpath)
def __init__(self, etree, modern=True, lxml=False)
def __init__(self, path, is_root=True)
def unstrip(self, elem, current_ns=None, copied=False)
def __init__(self, etree, lxml_etree=False)
def strip(self, elem, preserve=True, current_ns=None, top=True)
Robot Framework library for verifying and modifying XML documents.
def get_element_attributes(self, source, xpath='.')
Returns all attributes of the specified element.
def _find_parent(self, root, element)
def get_elements(self, source, xpath)
Returns a list of elements in the source matching the xpath.
def element_attribute_should_match(self, source, name, pattern, xpath='.', message=None)
Verifies that the specified attribute matches expected.
def __init__(self, use_lxml=False)
Import library with optionally lxml mode enabled.
def get_element_count(self, source, xpath='.')
Returns and logs how many elements the given xpath matches.
def get_element(self, source, xpath='.')
Returns an element in the source matching the xpath.
def _wrong_number_of_matches(self, count, xpath)
def _normalize_whitespace(self, text)
def element_should_not_have_attribute(self, source, name, xpath='.', message=None)
Verifies that the specified element does not have attribute name.
def get_element_attribute(self, source, name, xpath='.', default=None)
Returns the named attribute of the specified element.
def remove_elements_attributes(self, source, xpath='.')
Removes all attributes from the specified elements.
def element_attribute_should_be(self, source, name, expected, xpath='.', message=None)
Verifies that the specified attribute is expected.
def remove_element_attribute(self, source, name, xpath='.')
Removes attribute name from the specified element.
def set_element_text(self, source, text=None, tail=None, xpath='.')
Sets text and/or tail text of the specified element.
def remove_element(self, source, xpath='', remove_tail=False)
Removes the element matching xpath from the source structure.
def set_elements_tag(self, source, tag, xpath='.')
Sets the tag of the specified elements.
def set_elements_attribute(self, source, name, value, xpath='.')
Sets attribute name of the specified elements to value.
def add_element(self, source, element, index=None, xpath='.')
Adds a child element to the specified element.
def get_elements_texts(self, source, xpath, normalize_whitespace=False)
Returns text of all elements matching xpath as a list.
def _yield_texts(self, element, top=True)
def _preserve_tail(self, element, parent)
def element_should_not_exist(self, source, xpath='.', message=None)
Verifies that no element match the given xpath.
def element_should_exist(self, source, xpath='.', message=None)
Verifies that one or more element match the given xpath.
def set_element_attribute(self, source, name, value, xpath='.')
Sets attribute name of the specified element to value.
def element_text_should_be(self, source, expected, xpath='.', normalize_whitespace=False, message=None)
Verifies that the text of the specified element is expected.
def parse_xml(self, source, keep_clark_notation=False, strip_namespaces=False)
Parses the given XML file or string into an element structure.
def set_element_tag(self, source, tag, xpath='.')
Sets the tag of the specified element.
def _raise_wrong_number_of_matches(self, count, xpath, message=None)
def copy_element(self, source, xpath='.')
Returns a copy of the specified element.
def save_xml(self, source, path, encoding='UTF-8')
Saves the given element to the specified file.
def elements_should_match(self, source, expected, exclude_children=False, normalize_whitespace=False)
Verifies that the given source element matches expected.
def remove_elements(self, source, xpath='', remove_tail=False)
Removes all elements matching xpath from the source structure.
def log_element(self, source, level='INFO', xpath='.')
Logs the string representation of the specified element.
def _remove_element(self, root, element, remove_tail=False)
def clear_element(self, source, xpath='.', clear_tail=False)
Clears the contents of the specified element.
def remove_element_attributes(self, source, xpath='.')
Removes all attributes from the specified element.
def _compare_elements(self, source, expected, comparator, exclude_children, normalize_whitespace)
def element_to_string(self, source, xpath='.', encoding=None)
Returns the string representation of the specified element.
def get_element_text(self, source, xpath='.', normalize_whitespace=False)
Returns all text of the element, possibly whitespace normalized.
def set_elements_text(self, source, text=None, tail=None, xpath='.')
Sets text and/or tail text of the specified elements.
def element_text_should_match(self, source, pattern, xpath='.', normalize_whitespace=False, message=None)
Verifies that the text of the specified element matches expected.
def remove_elements_attribute(self, source, name, xpath='.')
Removes attribute name from the specified elements.
def get_child_elements(self, source, xpath='.')
Returns the child elements of the specified element as a list.
def evaluate_xpath(self, source, expression, context='.')
Evaluates the given xpath expression and returns results.
def elements_should_be_equal(self, source, expected, exclude_children=False, normalize_whitespace=False)
Verifies that the given source element is equal to expected.
def is_truthy(item)
Returns True or False depending on is the item considered true or not.
def is_falsy(item)
Opposite of :func:is_truthy.
def get_version(naked=False)