#-*- coding: utf-8 -*- # Copyright 2008-2010 Mir Calculate Ltd. http://www.calculate-linux.org # # Licensed 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. import sys from xml import xpath import xml.dom.minidom from cl_utils import _error # Перевод cообщений модуля from cl_lang import lang tr = lang() tr.setLocalDomain('cl_lib') tr.setLanguage(sys.modules[__name__]) class xml_xfce(_error): """Класс для объединения xfce-xml файлов""" # root нода rootNode = False # body нода bodyNode = False # Документ doc = False # Текст шаблона text = "" # Комментарий _comment = ("") def __init__(self, text): self.text = text # Создаем пустой объект self.docObj = type("_empty_class", (object,), {})() # Названия аттрибутов для пустого объекта emptyMethods = ["getNodeBody","removeComment","insertBRtoBody", "insertBeforeSepAreas"] # Добавляем необходимые аттрибуты пустому объекту for method in emptyMethods: setattr(self.docObj, method, self.emptyMethod) # Создаем XML документ self.doc = self.textToXML() def emptyMethod(self, *arg , **argv): """Пустой метод""" return True def setNameBodyNode(self, name): """Устанавливает название для корневой ноды документа""" if not self.bodyNode: return False self.bodyNode.setAttribute("name", name) return True def textToXML(self): """Создание из текста XML документа Храним xml в своем формате """ if not self.text.strip(): self.text = ''' ''' try: self.doc = xml.dom.minidom.parseString(self.text) except: self.setError(_("Can not text template is XML")) return False self.rootNode = self.doc.documentElement self.bodyNode = self.rootNode return self.doc def join(self, xml_xfceObj): """Объединяем конфигурации""" if isinstance(xml_xfceObj, xml_xfce): try: self.joinDoc(xml_xfceObj.doc) except: self.setError(_("Can not join template")) return False return True def _removeDropNodesAndAttrAction(self, xmlNode): """Удаляет ноды с аттрибутом action='drop' Также удаляет аттрибут action у всех нод """ flagError = False childNodes = xmlNode.childNodes if xmlNode.nodeType ==xmlNode.ELEMENT_NODE: if xmlNode.hasAttribute("action"): nAction = xmlNode.getAttribute("action") if not nAction in ("join","replace","drop"): textError = _('''In the text, XML template, look \ for a reserved attribute 'action' with the incorrect value.\n\ Valid values attribute 'action': \ (action="join", action="replace", action="drop")''') self.setError(textError) return False xmlNode.removeAttribute("action") if nAction == "drop": parentNode = xmlNode.parentNode if parentNode: parentNode.removeChild(xmlNode) if childNodes: for node in childNodes: if not self._removeDropNodesAndAttrAction(node): flagError = True break if flagError: return False return True def postXML(self): """Последующая постобработка XML""" # Удаляем теги action и удаляемые ноды self._removeDropNodesAndAttrAction(self.bodyNode) def _join(self, xmlNewNode, xmlOldNode, flagRootNode=True): """Объединение корневой ноды шаблона и корневой ноды файла""" xmlNode = xmlNewNode childNodes = xmlNode.childNodes nextOldNode = xmlOldNode flagError = False if xmlNode.nodeType ==xmlNode.ELEMENT_NODE: n = xmlNode path = u'' nName = u'' nType = u'' nValue = u'' nAction = u'' attrName = '' attrType = '' path = n.tagName if n.hasAttribute("name"): nName = n.getAttribute("name") attrName = u"attribute::name='%s'"%nName if n.hasAttribute("type"): nType = n.getAttribute("type") attrType = u"attribute::type='%s'"%nType if n.hasAttribute("value"): nValue = n.getAttribute("value") if n.hasAttribute("action"): nAction = n.getAttribute("action") if not nAction in ("join","replace","drop"): textError = _('''In the text, XML template, look \ for a reserved attribute 'action' with the incorrect value.\n\ Valid values attribute 'action': \ (action="join", action="replace", action="drop")''') self.setError(textError) return False if xmlOldNode.parentNode: strAttr = [attrName, attrType] findAttr = filter(lambda x: x, strAttr) findAttrStr = '' if findAttr: strAttr = u' and '.join(findAttr) findAttrStr = "[%s]"%strAttr findPath = u"child::%s%s"%(path,findAttrStr) # Рабочая нода if flagRootNode: workNode = xmlOldNode.parentNode else: workNode = xmlOldNode oldNodes = xpath.Evaluate(findPath, workNode) # Новая нода список flagArray = False if nType == "array": flagArray = True flagDrop = False flagJoin = True flagReplace = False if nAction == "replace": flagJoin = False flagReplace = True elif nAction == "drop": flagJoin = False flagDrop = True if flagRootNode: textError = _('Incorrect action="drop" in root node') self.setError(textError) return False if oldNodes: if len(oldNodes)>1: textError = _("The uncertainty in this template are \ the same nodes at one level") self.setError(textError) return False nextOldNode = oldNodes[0] # Замещаем ноду в случае массива if flagArray and not flagDrop: replaceXmlNode = xmlNode.cloneNode(True) if nAction: replaceXmlNode.removeAttribute("action") workNode.replaceChild(replaceXmlNode, nextOldNode) flagJoin = False flagReplace = False childNodes = False # Объединение нод if flagJoin: if nextOldNode.hasAttribute("value"): oValue = nextOldNode.getAttribute("value") if nValue != oValue: nextOldNode.setAttribute("value",nValue) # Замещение ноды elif flagReplace: replaceXmlNode = xmlNode.cloneNode(True) if not\ self._removeDropNodesAndAttrAction(replaceXmlNode): return False workNode.replaceChild(replaceXmlNode, nextOldNode) childNodes = False # Удаление ноды elif flagDrop: workNode.removeChild(nextOldNode) childNodes = False else: # Добавление ноды childNodes = False if not flagDrop: appendXmlNode = xmlNode.cloneNode(True) if not\ self._removeDropNodesAndAttrAction(appendXmlNode): return False workNode.appendChild(appendXmlNode) if childNodes: for node in childNodes: if not self._join(node, nextOldNode, False): flagError = True break if flagError: return False return True def joinDoc(self, doc): """Объединение документа шаблона и документа файла""" if not self.doc: self.setError(_("Can not text file is XML")) return False if not doc: self.setError(_("Can not text template is XML")) return False # Импортируем корневую ноду нового документа в текущий документ #newImportBodyNode = self.doc.importNode(doc.documentElement, True) # Объединение корневой ноды шаблона и корневой ноды файла if not self._join(doc.documentElement, self.bodyNode): return False return True def getConfig(self): """Получение текстового файла из XML документа""" data = self.doc.toprettyxml(encoding='UTF-8').split("\n") data = filter(lambda x: x.strip(), data) return "\n".join(data).replace("\t"," ").decode("UTF-8")