def _create_xml_node(xast, node, context, insert_index=None): if isinstance(xast, ast.Step): if isinstance(xast.node_test, ast.NameTest): # check the predicates (if any) to verify they're constructable for pred in xast.predicates: if not _predicate_is_constructible(pred): msg = ( "Missing element for '%s', and node creation is " + "supported only for simple child and attribute " + "nodes with simple predicates." ) % (serialize(xast),) raise Exception(msg) # create the node itself if xast.axis in (None, "child"): new_node = _create_child_node(node, context, xast, insert_index) elif xast.axis in ("@", "attribute"): new_node = _create_attribute_node(node, context, xast) # and create any nodes necessary for the predicates for pred in xast.predicates: _construct_predicate(pred, new_node, context) return new_node # if this is a text() node, we don't need to create anything further # return the node that will be parent to text() elif _is_text_nodetest(xast): return node elif isinstance(xast, ast.BinaryExpression): if xast.op == "/": left_xpath = serialize(xast.left) left_node = _find_xml_node(left_xpath, node, context) if left_node is None: left_node = _create_xml_node(xast.left, node, context) return _create_xml_node(xast.right, left_node, context) # anything else, throw an exception: msg = ( "Missing element for '%s', and node creation is supported " + "only for simple child and attribute nodes." ) % (serialize(xast),) raise Exception(msg)
def set(self, xpath, xast, node, context, mapper, value): xvalue = mapper.to_xml(value) match = _find_xml_node(xpath, node, context) if xvalue is None: # match must be None. if it exists, delete it. if match is not None: removed = _remove_xml(xast, node, context) # if a node can't be removed, warn since it could have unexpected results if not removed: logger.warn("""Could not remove xml for '%s' from %r""" % (serialize(xast), node)) else: if match is None: match = _create_xml_node(xast, node, context) # terminal (rightmost) step informs how we update the xml step = _find_terminal_step(xast) _set_in_xml(match, xvalue, context, step)
def _remove_xml(xast, node, context): "Remove a node or attribute; returns True when something is deleted" if isinstance(xast, ast.Step): if isinstance(xast.node_test, ast.NameTest): if xast.axis in (None, "child"): return _remove_child_node(node, context, xast) elif xast.axis in ("@", "attribute"): return _remove_attribute_node(node, context, xast) # special case for text() # since it can't be removed, at least clear out any value in the text node elif _is_text_nodetest(xast): node.text = "" return True elif isinstance(xast, ast.BinaryExpression): if xast.op == "/": left_xpath = serialize(xast.left) left_node = _find_xml_node(left_xpath, node, context) if left_node is not None: return _remove_xml(xast.right, left_node, context) return False
def round_trip(self, xpath_str): xp = xpath.parse(xpath_str) self.assertEqual(xpath_str, serialize(xp))
def _remove_child_node(node, context, xast): xpath = serialize(xast) child = _find_xml_node(xpath, node, context) if child is not None: node.remove(child) return True