#-*- coding: utf-8 -*- # Copyright 2008-2010 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 re import types import copy from xml import xpath from cl_template import xmlDoc from format.samba import samba class xmlDocPlasma: """Класс для замены метода joinArea в xmlDoc для plasma""" # заменяемый метод для xmlDoc def joinArea(self, baseNode, xmlNewArea): """Объединяет область c областью Body (xmlNewArea c baseNode)""" def appendArea(baseNode, xmlNewArea): fieldsRemove = xpath.Evaluate(\ "descendant::field[child::action='drop']", xmlNewArea) for rmNode in fieldsRemove: parentNode = rmNode.parentNode parentNode.removeChild(rmNode) captionAreasRemove = xpath.Evaluate(\ "descendant::area/child::caption[child::action='drop']", xmlNewArea) for rmNodeCapt in captionAreasRemove: rmNode = rmNodeCapt.parentNode parentNode = rmNode.parentNode parentNode.removeChild(rmNode) self.setActionArea(xmlNewArea, "append") # Добавляем разделитель областей во вложенные области areaNodes = xpath.Evaluate('descendant::area',xmlNewArea) for areaNode in areaNodes: self.setActionArea(areaNode,"append") parentNode = areaNode.parentNode parentNode.insertBefore(self.sepAreas.cloneNode(True), areaNode) baseNode.appendChild(xmlNewArea) # Добавляем разделитель областей baseNode.insertBefore(self.sepAreas.cloneNode(True), xmlNewArea) nodesNames = xpath.Evaluate('child::area/caption/name',baseNode) nodesNewArea = xpath.Evaluate('child::caption/name',xmlNewArea) if not nodesNames: # Добавляем область if nodesNewArea: newAreaAction = self.getActionArea(xmlNewArea) if not (newAreaAction == "drop"): appendArea(baseNode, xmlNewArea) return True if not nodesNames or not nodesNewArea: return False nameArea = "" if nodesNewArea[0].firstChild: nameArea = nodesNewArea[0].firstChild.nodeValue.strip() flagFindArea = False baseNodes = [] for oName in nodesNames: newAreaAction = self.getActionArea(xmlNewArea) oArea = oName.parentNode.parentNode oNameTxt = "" if oName.firstChild: oNameTxt = oName.firstChild.nodeValue if nameArea == oNameTxt: flagFindArea = True # При использовании удаления if newAreaAction == "drop": prevNode = oName.parentNode.parentNode.previousSibling removePrevNodes = [] while (prevNode) and self.getTypeField(prevNode) == "br": removePrevNodes.append(prevNode) prevNode = prevNode.previousSibling for removeNode in removePrevNodes: baseNode.removeChild(removeNode) baseNode.removeChild(oName.parentNode.parentNode) continue elif newAreaAction == "replace": oldAreaNode = oName.parentNode.parentNode newAreaCaption = xpath.Evaluate('child::caption', xmlNewArea)[0] oldAreaCaption = xpath.Evaluate('child::caption', oldAreaNode)[0] if newAreaCaption and oldAreaCaption: xmlNewArea.replaceChild(oldAreaCaption,newAreaCaption) self.setActionArea(xmlNewArea,"replace") baseNode.replaceChild(xmlNewArea, oldAreaNode) continue baseNodes.append(oName.parentNode.parentNode) # Заменяем QUOTE oldAreaNode = oName.parentNode.parentNode oldAreaQuote = xpath.Evaluate('child::caption/quote', oldAreaNode)[0] if oldAreaQuote and\ not oldAreaQuote.firstChild: newAreaQuote = xpath.Evaluate('child::caption/quote', xmlNewArea)[0] oldAreaCaption = xpath.Evaluate('child::caption', oldAreaNode)[0] if newAreaQuote and oldAreaCaption: oldAreaCaption.replaceChild(newAreaQuote, oldAreaQuote) newFields = xpath.Evaluate('child::field',xmlNewArea) joinNewFields = xpath.Evaluate(\ "child::field[child::action='join']" ,xmlNewArea) self.addNewFielsOldArea(newFields, joinNewFields, oArea) if not flagFindArea: # Добавляем область if not (newAreaAction == "drop"): appendArea(baseNode, xmlNewArea) else: tmpXmlNewAreas = xpath.Evaluate('child::area',xmlNewArea) for na in tmpXmlNewAreas: for bn in baseNodes: self.joinArea(bn, na) return True class plasma(samba): """Класс для обработки конфигурационного файла типа kde """ _comment = "#" configName = "plasma" configVersion = "0.1" reHeader = re.compile("^[\t ]*\[[^\[\]]+\].*\n?",re.M) reBody = re.compile(".+",re.M|re.S) reComment = re.compile("^\s*%s.*"%(_comment)) reSeparator = re.compile("=") sepFields = "\n" reSepFields = re.compile(sepFields) def __init__(self,text): samba.__init__(self,text) # Делим текст на области включая вложенные (areas массив областей) def splitToAllArea(self, text, areas): """Делит текст на области включая вложенные возвращает список объектов областей (переменная areas) """ class area: def __init__(self): self.header = False self.start = False self.fields = [] self.end = False def findPathArea(listPath, areaF): """Ищет путь в области areaF - объект area listPath - cписок названий областей """ ret = False if not listPath: return ret flagList = False if type(areaF) == types.ListType: fields = areaF flagList = True else: fields = areaF.fields if areaF.header == listPath[0]: ret = areaF else: return ret for i in fields: if str(i.__class__.__name__) == "area": add = False if not flagList: add = listPath.pop(0) if not listPath: break ret = False if i.header == listPath[0]: ret = findPathArea(listPath, i) break else: if add: listPath.insert(0,add) if ret == areaF and len(listPath)>1: ret = False return ret blTmp = self.blocTextObj.findBloc(self.text,self.reHeader,self.reBody) blocs = self.getFullAreas(blTmp) reH = re.compile("\[([^\[\]]+)\]") # Список имен блоков namesBlockList = [] # Временные поля fieldsTmp = [] # Добавляем заголовки z = 0 for h in blocs[0]: if not h: if blocs[1][z] == "": fieldsTmp.append("") #fieldsTmp.append("\n") else: fieldsTmp.append(blocs[1][z]) z += 1 continue z += 1 slpNamesBlock = reH.split(h) # Отступ слева для заголовка indentionLeft = slpNamesBlock[0] namesBlock = filter(lambda x: x.strip(), slpNamesBlock) #namesBlock = map(lambda x: self.removeSymbolTerm(x), namesBlock) findArea = findPathArea(copy.copy(namesBlock), areas) namesBlockList.append(namesBlock) if findArea: if len(namesBlock) > 1: namesBlockView = map(lambda x: self.removeSymbolTerm(x), namesBlock) else: namesBlockView = namesBlock findArea.start = indentionLeft + "[" + \ "][".join(namesBlockView) + "]" else: i = 0 lenNamesBlock = len(namesBlock) namesBlockTmp = [] for nameB in namesBlock: namesBlockTmp.append(nameB) findArea = findPathArea(copy.copy(namesBlockTmp), areas) i += 1 if not findArea: areaNew = area() areaNew.header = nameB if lenNamesBlock == i: if len(namesBlock) > 1: namesBlockView = map(\ lambda x: self.removeSymbolTerm(x), namesBlock) else: namesBlockView = namesBlock areaNew.start = indentionLeft + "[" + \ "][".join(namesBlockView) + "]" else: areaNew.start = "" areaNew.end = "" if i == 1: if lenNamesBlock == i: areas += fieldsTmp areas.append(areaNew) findAreaPrev = areas[-1] else: if lenNamesBlock == i: findAreaPrev.fields += fieldsTmp findAreaPrev.fields.append(areaNew) findAreaPrev = findAreaPrev.fields[-1] else: findAreaPrev = findArea fieldsTmp = [] i = 0 delt = 0 # Добавляем тела for body in blocs[1]: if not blocs[0][i]: i += 1 delt +=1 continue ## В случае последнего комментария не добавляем перевод строки #if self.reComment.search(body.splitlines()[-1]): body = "\n" + body namesBlock = namesBlockList[i-delt] findArea = findPathArea(copy.copy(namesBlock), areas) if findArea: #if findArea.fields: #if type(findArea.fields[0]) == types.StringType: #findArea.fields.pop(0) findArea.fields.insert(0, body) i += 1 return areas def createCaptionTerm(self, header, start, end, docObj): """Создание пустой области с заголовком при создании области проверяется первый символ заголовка и добавляется тег action "!" - drop "-" - replace """ areaAction = False if header: if header[0] == "!": docObj.createCaption(header[1:], [start, end.replace("\n","")]) areaAction = "drop" elif header[0] == "-": docObj.createCaption(header[1:], [start, end.replace("\n","")]) areaAction = "replace" else: docObj.createCaption(header, [start, end.replace("\n","")]) else: docObj.createCaption(header, [start, end.replace("\n","")]) areaXML = docObj.createArea() if areaAction: docObj.setActionArea(areaXML, areaAction) return areaXML def createXML(self, areas, rootNode, docObj): """Создаем из массивов областей XML""" for i in areas: if str(i.__class__.__name__) == "area": if i.header: areaXML = self.createCaptionTerm(i.header, i.start, i.end.replace("\n",""), docObj) for f in i.fields: if str(f.__class__.__name__) == "area": if f.header: areaXMLChild = self.createCaptionTerm(f.header, f.start, f.end.replace("\n",""), docObj) self.createXML(f.fields, areaXMLChild, docObj) areaXML.appendChild(areaXMLChild) else: self.createXML(f.fields, areaXML, docObj) if "\n" in f.end: fieldXMLBr = docObj.createField("br",[], "",[], False, False) areaXML.appendChild(fieldXMLBr) else: if not f: continue fields = self.splitToFields(f) for field in fields: if field.name != False: fieldXML = self.createFieldTerm(field.name, field.value, field.br, docObj) areaXML.appendChild(fieldXML) if field.br[-1] == "\n": fieldXMLBr = docObj.createField("br",[], "",[], False, False) areaXML.appendChild(fieldXMLBr) elif field.comment != False: fieldXML = docObj.createField("comment", [field.comment], "", [], False, False) areaXML.appendChild(fieldXML) elif field.br != False: brText = field.br.replace("\n","") if brText: fieldXML = docObj.createField('br', [brText], "", [], False, False) else: fieldXML = docObj.createField('br', [], "", [], False, False) if areaXML: areaXML.appendChild(fieldXML) if i.header: rootNode.appendChild(areaXML) if "\n" in i.end: fieldXMLBr = docObj.createField("br",[], "",[], False, False) rootNode.appendChild(fieldXMLBr) else: if not i: continue fields = self.splitToFields(i) for field in fields: if field.name != False: fieldXML = self.createFieldTerm(field.name, field.value, field.br, docObj) rootNode.appendChild(fieldXML) if field.br[-1] == "\n": fieldXMLBr = docObj.createField("br",[],"", [], False, False) rootNode.appendChild(fieldXMLBr) elif field.comment != False: fieldXML = docObj.createField("comment", [field.comment], "", [], False, False) rootNode.appendChild(fieldXML) elif field.br != False: brText = field.br.replace("\n","") if brText: fieldXML = docObj.createField('br', [brText],"",[], False, False) else: fieldXML = docObj.createField('br', [], "", [], False, False) rootNode.appendChild(fieldXML) #rootNode.appendChild(areaXML) def createTxtConfig(self, strHeader, dictVar): """Cоздает область с заголовком создает текст конфигурационного файла в формате samba из заголовка (строка) и словаря переменных """ if not strHeader: return "" if type(strHeader) in (tuple, list): outTxt = "".join(map(lambda x: "["+x+"]",strHeader)) if not outTxt: return "" outTxt += "\n" else: outTxt = "[" + strHeader + "]\n" for key in dictVar.keys(): outTxt += "%s=%s\n" %(key,dictVar[key]) return outTxt def _textToXML(self): """Преобразуем текст в XML""" areas = [] if self.text.strip(): self.splitToAllArea(self.text, areas) #docObj = xmlDoc() # Создаем новый класс xmlDoc с измененным методом joinArea newClass = type("newXmlDocPlalma",(xmlDocPlasma,xmlDoc,object),{}) # Создаем экземпляр нового класса docObj = newClass() # Создание объекта документ c пустым разделителем между полями docObj.createDoc(self.configName, self.configVersion) if not areas: return docObj self.createXML(areas, docObj.getNodeBody(), docObj) return docObj def postXML(self): """Последующая постобработка XML""" # Для добавления перевода строки между областями если его нет def getQuotesArea(xmlArea): quotes = [] xmlQuotes = xpath.Evaluate('child::caption/quote',xmlArea) for node in xmlQuotes: if node.firstChild: quotes.append(node.firstChild.nodeValue) if len(quotes) == 0: quotes.append("") quotes.append("") elif len(quotes) == 1: quotes.append("") return quotes xmlAreas = xpath.Evaluate("descendant::area", self.docObj.body) for xmlArea in xmlAreas: # Перед пустой областью и после нее удаляем переводы строк if getQuotesArea(xmlArea) == ["",""]: if xmlArea.previousSibling and\ self.docObj.getTypeField(xmlArea.previousSibling) == "br": parentNode = xmlArea.previousSibling.parentNode if xmlArea.previousSibling.previousSibling and\ self.docObj.getTypeField(xmlArea.previousSibling.previousSibling) == "br": parentNode.removeChild(\ xmlArea.previousSibling.previousSibling) parentNode.removeChild(xmlArea.previousSibling) if xmlArea.nextSibling and\ self.docObj.getTypeField(xmlArea.nextSibling) == "br": parentNode = xmlArea.nextSibling.parentNode if xmlArea.nextSibling.nextSibling and\ self.docObj.getTypeField(xmlArea.nextSibling.nextSibling) == "br": parentNode.removeChild(xmlArea.nextSibling.nextSibling) parentNode.removeChild(xmlArea.nextSibling) continue # Собираем поля в кучку xmlChildAreas = xpath.Evaluate("child::area", xmlArea) if xmlChildAreas: childNodes = self.docObj.getFieldsArea(xmlArea) firstChildArea = xmlChildAreas[0] if firstChildArea.previousSibling and\ self.docObj.getTypeField(firstChildArea.previousSibling)=="br": if firstChildArea.previousSibling.previousSibling: if self.docObj.getTypeField(\ firstChildArea.previousSibling.previousSibling)=="br": firstChildArea = firstChildArea.previousSibling flagFoundArea = False it = 0 lenChild = len(childNodes) for node in childNodes: it += 1 if node.tagName == "area": flagFoundArea = True continue if flagFoundArea and node.tagName == "field": if self.docObj.getTypeField(node) == "var": xmlArea.insertBefore(node, firstChildArea) if it < lenChild: if self.docObj.getTypeField(childNodes[it])==\ "br": xmlArea.insertBefore(childNodes[it], firstChildArea) # Добавление перевода строк в если его нет между полями if self.docObj.getTypeField(node) == "var" and\ node.previousSibling and\ not (self.docObj.getTypeField(node.previousSibling) in\ ("br","comment")): xmlArea.insertBefore(self.docObj.createField("br", [],"",[], False,False), node) # Добавляем BR если его нет первым полем xmlFields = xpath.Evaluate("child::field", xmlArea) if not (xmlFields and\ (self.docObj.getTypeField(xmlFields[0]) == "br" or\ self.docObj.getTypeField(xmlFields[0]) == "comment")): if xmlFields: xmlArea.insertBefore(self.docObj.createField("br", [],"",[], False,False), xmlFields[0]) # Добавление переводов строк между полями if xmlFields: for node in xmlFields: # Добавление перевода строк в если его нет между полями if self.docObj.getTypeField(node) == "var" and\ node.previousSibling and\ not (self.docObj.getTypeField(node.previousSibling) in\ ("br","comment")): xmlArea.insertBefore(self.docObj.createField("br", [],"",[], False, False), node) # Если последним полем BR, удаляем его if xmlFields and self.docObj.getTypeField(xmlFields[-1]) == "br": if not xmlFields[-1].nextSibling: xmlArea.removeChild(xmlFields[-1]) # Если предыдущим полем не (BR или комментарий) - добавляем BR if xmlArea.previousSibling and\ not (self.docObj.getTypeField(xmlArea.previousSibling) == "br" or\ self.docObj.getTypeField(xmlArea.previousSibling) == "comment"): parentNode = xmlArea.parentNode parentNode.insertBefore(self.docObj.createField("br", [],"",[], False,False), xmlArea) # Если есть предыдущее поле, и поле предыдущеее предыдущему # не равно BR или комментарий то добавляем BR if xmlArea.previousSibling: prPrSibling = xmlArea.previousSibling.previousSibling if prPrSibling and\ not (self.docObj.getTypeField(prPrSibling) == "br" or\ self.docObj.getTypeField(prPrSibling) == "comment"): parentNode = xmlArea.parentNode parentNode.insertBefore(self.docObj.createField("br", [],"",[], False,False), xmlArea) # Если после есть BR а за ним ничего нет, удаляем BR if xmlArea.nextSibling and\ self.docObj.getTypeField(xmlArea.nextSibling) == "br": if not xmlArea.nextSibling.nextSibling: parentNode = xmlArea.nextSibling.parentNode parentNode.removeChild(xmlArea.nextSibling) def join(self, kdeObj): """Объединяем конфигурации""" if isinstance(kdeObj, plasma): self.docObj.joinDoc(kdeObj.doc) self.postXML()