Source code for networkapi.infrastructure.xml_utils

# -*- coding: utf-8 -*-
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements.  See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License.  You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from xml.dom import InvalidCharacterErr
from xml.dom.minicompat import StringTypes
from xml.dom.minidom import *


[docs]class XMLError(Exception): """Representa um erro ocorrido durante o marshall ou unmarshall do XML.""" def __init__(self, cause, message): self.cause = cause self.message = message def __str__(self): msg = u'Erro ao criar ou ler o XML: Causa: %s, Mensagem: %s' % ( self.cause, self.message) return msg.encode('utf-8', 'replace')
[docs]class InvalidNodeNameXMLError(XMLError): """Nome inválido para representá-lo como uma TAG de XML.""" def __init__(self, cause, message): XMLError.__init__(self, cause, message)
[docs]class InvalidNodeTypeXMLError(XMLError): """Tipo inválido para o conteúdo de uma TAG de XML.""" def __init__(self, cause, message): XMLError.__init__(self, cause, message)
def _add_text_node(value, node, doc): if value is None: return if not isinstance(value, StringTypes): text = '%s' % unicode(value) else: text = r'%s' % value.replace('%', '%%') try: textNode = doc.createTextNode(text) node.appendChild(textNode) except TypeError, t: raise InvalidNodeTypeXMLError( t, u'Conteúdo de um Nó do XML com tipo de dado inválido: %s ' % value) def _add_list_node(nodeName, list, parent, doc): if list: for value in list: node = doc.createElement(nodeName) parent.appendChild(node) if isinstance(value, dict): _add_nodes_to_parent(value, node, doc) else: _add_text_node(value, node, doc) else: node = doc.createElement(nodeName) parent.appendChild(node) _add_text_node('', node, doc) def _add_nodes_to_parent(map, parent, doc): if map is None: return for key, value in map.iteritems(): try: if isinstance(value, dict): node = doc.createElement(key) parent.appendChild(node) _add_nodes_to_parent(value, node, doc) elif isinstance(value, type([])): _add_list_node(key, value, parent, doc) else: node = doc.createElement(key) parent.appendChild(node) _add_text_node(value, node, doc) except InvalidCharacterErr, i: raise InvalidNodeNameXMLError( i, u'Valor inválido para nome de uma TAG de XML: %s' % key)
[docs]def dumps(map, root_name, root_attributes=None): """Cria um string no formato XML a partir dos elementos do map. Os elementos do mapa serão nós filhos do root_name. Cada chave do map será um Nó no XML. E o valor da chave será o conteúdo do Nó. Throws: XMLError, InvalidNodeNameXMLError, InvalidNodeTypeXMLError """ xml = '' try: implementation = getDOMImplementation() except ImportError, i: raise XMLError(i, u'Erro ao obter o DOMImplementation') doc = implementation.createDocument(None, root_name, None) try: root = doc.documentElement if (root_attributes is not None): for key, value in root_attributes.iteritems(): attribute = doc.createAttribute(key) attribute.nodeValue = value root.setAttributeNode(attribute) _add_nodes_to_parent(map, root, doc) xml = doc.toxml('UTF-8') except InvalidCharacterErr, i: raise InvalidNodeNameXMLError( i, u'Valor inválido para nome de uma TAG de XML: %s' % root_name) finally: doc.unlink() return xml
[docs]def dumps_networkapi(map, version='1.0'): return dumps(map, 'networkapi', {'versao': version})
def _create_childs_map(parent, force_list): if parent is None: return None if parent.hasChildNodes(): childs = parent.childNodes childs_map = dict() childs_values = [] for i in range(childs.length): child = childs.item(i) if child.nodeType == Node.ELEMENT_NODE: if child.nodeName in childs_map: child_value = _create_childs_map(child, force_list) if child_value is not None: value = childs_map[child.nodeName] if not isinstance(value, type([])): value = [value] value.append(child_value) childs_map[child.nodeName] = value elif child.nodeName in force_list: child_value = _create_childs_map(child, force_list) if child_value is None: child_value = [] else: child_value = [child_value] childs_map[child.nodeName] = child_value else: childs_map[child.nodeName] = _create_childs_map( child, force_list) elif child.nodeType == Node.TEXT_NODE or child.nodeType == Node.CDATA_SECTION_NODE: if child.data.strip() != '': childs_values.append(child.data.replace('%%', '%')) if len(childs_values) == 0 and len(childs_map) == 0: return None if len(childs_values) != 0 and len(childs_map) != 0: childs_values.append(childs_map) return childs_values if len(childs_values) != 0: if len(childs_values) == 1: return childs_values[0] return childs_values return childs_map elif parent.nodeType == Node.TEXT_NODE or parent.nodeType == Node.CDATA_SECTION_NODE: if parent.data.strip() != '': return parent.data return None
[docs]def loads(xml, force_list=None): """Cria um dict com os dados do element root. O dict terá como chave o nome do element root e como valor o conteúdo do element root. Quando o conteúdo de um element é uma lista de Nós então o valor do element será um dict com uma chave para cada nó. Entretanto, se existir nós, de um mesmo pai, com o mesmo nome, então eles serão armazenados uma mesma chave do dict que terá como valor uma lista. Se o element root tem atributo, então também retorna um dict com os atributos. Throws: XMLError """ if force_list is None: force_list = [] try: doc = parseString(xml) except Exception, e: raise XMLError(e, u'Falha ao realizar o parse do xml.') root = doc.documentElement map = dict() attrs_map = dict() if root.hasAttributes(): attributes = root.attributes for i in range(attributes.length): attr = attributes.item(i) attrs_map[attr.nodeName] = attr.nodeValue map[root.nodeName] = _create_childs_map(root, force_list) return map, attrs_map
if __name__ == '__main__': map, attrs_map = loads('<teste/>') print map list = [{'id': None}, {'id': (2, 6)}] map = {'ambiente': list} xml = dumps(map, 'networkapi', {'versao': '1.0'}) print xml map, attrs_map = loads(xml) print map xml = '<?xml version="1.0" encoding="UTF-8"?><networkapi versao="1.0"><!--Comentario--><ambiente><id><!--Comentario--></id></ambiente><ambiente><id>3<teste>geovana</teste>2</id></ambiente></networkapi>' map, attrs_map = loads(xml) print map xml = '<?xml version="1.0" encoding="UTF-8"?><networkapi versao="1.0"><!--Comentario--><ambiente><id><!--Comentario--></id></ambiente><ambiente><id>3 2 5</id></ambiente></networkapi>' map, attrs_map = loads(xml) print map xml = dumps(map, 'networkapi', attrs_map) print xml xml = dumps(None, 'networkapi', {'versao': '1.0'}) print xml xml = """<?xml version="1.0" encoding="UTF-8"?> <networkapi versao="1.0"> <equipamento> <id_tipo_equipamento>1</id_tipo_equipamento> <id_modelo>teste</id_modelo> <nome>teste</nome> <id_grupo>teste</id_grupo> </equipamento> </networkapi>""" map, attrs_map = loads(xml) print map print dumps(map, 'networkapi', attrs_map) xml = """<?xml version="1.0" encoding="UTF-8"?> <networkapi versao="1.0"> <equipamento> <id ></id> </equipamento> <equipamento_grupo> <id></id> </equipamento_grupo> </networkapi> """ map, attrs_map = loads(xml) print map print dumps(map, 'networkapi', attrs_map) xml = """<?xml version="1.0" encoding="UTF-8"?> <networkapi versao="1.0"> <x/> </networkapi> """ map, attrs_map = loads(xml) print map print dumps(map, 'networkapi', attrs_map)