#/** # * # * 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 logging import re from xml.dom import minidom class WikiTextConverter: logger = logging.getLogger(__name__) CLASS_HEADER = """ {{NeedsExamples}}
__TOC__
""" METHODS_HEADER = "== Methods ==\n\n" FIELDS_HEADER = "== Fields ==\n\n" def __init__(self, specVersion): self.specVersion = specVersion # Converts the given spec node, which represents a class, into text for a wiki page # # param specClass a minidom.Node containing class info in spec format # returns a string containing wiki markup for the class def convertClass(self, specClass): # add the header wikiText = self.CLASS_HEADER # add the class name className = specClass.getAttribute("title") wikiText += '' + className + '\n\n' # add the class description for node in specClass.getElementsByTagName("t"): if node.parentNode.isSameNode(specClass): text = node.toxml().strip()[3:-4].strip() # strip the surrounding and tags text = self.__removeWhitespace(text) text = self.__convertLinks(text) wikiText += text.strip() + "\n\n" break # add the methods wikiText += self.METHODS_HEADER for node in specClass.getElementsByTagName("section"): # Ignore
elements that are children of subnodes if not node.parentNode.isSameNode(specClass): continue foundMethods = False if node.getAttribute("title") == "Method Details": foundMethods = True for methodNode in node.getElementsByTagName("section"): # Ignore
elements that are children of subnodes if not methodNode.parentNode.isSameNode(node): continue self.logger.info("Parsing %s method" % methodNode.getAttribute("anchor")) wikiText += "===%s===\n" % methodNode.getAttribute("anchor") wikiText += self.__getMethodSignature(methodNode) wikiText += self.__getMethodParameters(methodNode) wikiText += self.__getMethodReturns(methodNode) wikiText += self.__getMethodDescription(methodNode) break if not foundMethods: wikiText += "'''None'''\n\n" return wikiText def __getMethodSignature(self, methodNode): text = methodNode.getElementsByTagName('t')[0].toxml()[3:-4] text = self.__removeWhitespace(text) text = re.sub(r'Type: {((?s).*)} (.*)$', r'\1 \2', text) text = self.__convertLinks(text) return ':;%s\n\n' % text # Finds the parameters in the givenMethod node and converts them to wiki syntax. There are two # places the parameters can appear. First (and most common), is in a child element of the # method node that starts with 'Parameters:' (ignoring whitespace). Second (e.g. makeRequest), # is in a child
element o the method node (within a chilc # node). # # param methodNode a minidom.Node containing method info in spec format # returns a String containing the wikified text for listing the parameters def __getMethodParameters(self, methodNode): found = False; # Check for a child element that starts with 'Pareamters:' for node in methodNode.getElementsByTagName("t"): text = node.toxml().strip()[3:-4].strip() # strip the surrounding and tags if text.startswith("Parameters:"): text = text[11:] # Strip the leading 'Parameters:' string found = True; break # Check for a child
node if not found: for node in methodNode.getElementsByTagName("section"): if node.getAttribute('title') == 'Parameters': # The parameters
contains a elemented with the of parameters tNode = node.getElementsByTagName("t")[0] text = tNode.getElementsByTagName('texttable')[0].toxml() found = True; # If there are no parameters, don't include the Parameters heading in the wiki if not found: return '' parameterString = ":Parameters\n:" parameterString += self.__convertTable(text).strip() + "\n\n" return parameterString # Parses the first child node of the method node that starts with 'Returns:' def __getMethodReturns(self, methodNode): for node in methodNode.getElementsByTagName("t"): text = node.toxml().strip()[3:-4].strip() # strip the '' and '' tags if text.startswith("Returns:"): returnsString = ":Returns\n:" text = text[8:] # String the 'Returns:' returnsString += self.__convertTable(text).strip() + "\n\n" return returnsString return "" # Finds the method description and wikifies it. Usually the description is the first # child of the method node and any sub elements. Sometimes (e.g. makeRequest) the # description is longer and includes
elements after the initial . # # param methodNode a minidom.Node containing the spec-formatted info about the method # returns a String containing the wikified version of the text def __getMethodDescription(self, methodNode): wikiDesc = "" for node in methodNode.getElementsByTagName("t"): text = node.toxml()[3:-4].strip() # strip the '' and '' tags if text.startswith("Description:"): wikiDesc = text[12:].strip() wikiDesc = self.__convertCode(wikiDesc) wikiDesc = self.__convertLinks(wikiDesc) wikiDesc = re.sub(r'', r'

', wikiDesc) wikiDesc = re.sub(r'', r'

', wikiDesc) wikiDesc = self.__removeWhitespace(wikiDesc) break for node in methodNode.getElementsByTagName("section"): if node.getAttribute('title') == 'Parameters': continue wikiDesc += self.__convertExtendedDescription(node) wikiDesc = ":'''Description'''\n
""%s
\n" % wikiDesc #if methodNode.getAttribute('title') == 'makeRequest': # self.logger.info(wikiDesc) return wikiDesc # Parses a
element that contains an extended method description (e.g. makeRequest) # and returns a wikified string of text. def __convertExtendedDescription(self, descNode): text = self.__removeLeadingWhitespace(descNode.toxml()) text = self.__convertLinks(text) text = self.__convertLists(text) text = re.sub(r'
', r"'''\1'''", text) text = re.sub(r'', r'

', text) text = re.sub(r'', r'

', text) text = re.sub(r'
', r'', text) return text # Creates a new miniDom with a wikified version of the given list def __convertLists(self, descNodeText): descNode = minidom.parseString(descNodeText) for specListNode in descNode.getElementsByTagName('list'): if specListNode.getAttribute('style') == 'numbers': wikiListNode = minidom.Element('ol') else: wikiListNode = minidom.Element('ul') text = '' for node in specListNode.childNodes: if not node.hasChildNodes(): continue # ignore any Text nodes if node.tagName == 't': itemText = minidom.Text() itemText.data = self.__removeLeadingWhitespace(node.firstChild.data).strip() if node.getAttribute('hangText'): itemText.data = "'''%s''' - %s" % (node.getAttribute('hangText'), itemText.data) listItem = minidom.Element('li') listItem.appendChild(itemText) wikiListNode.appendChild(listItem) else: wikiListNode.appendChild(node) descNodeText = re.sub(r'', wikiListNode.toxml(), descNodeText) return descNodeText # Converts a spec table to a wiki table # # param text a string containing the spec-formatted table # returns a string containing the wiki-formatted table def __convertTable(self, text): text = re.sub(r'((?s).*)', r':\1
', text) text = re.sub(r']*>', r'
', text) text = self.__convertLinks(text) text = text.replace("", "") text = text.replace("", "") text = text.replace("", "") text = text.replace("", "") numColumns = text.count("") numCells = text.count("") # enclose the 's in a text = text[:text.find("")] + "" + text[text.find(""):] text = text[:text.rfind("")+5] + "" + text[text.rfind("")+5:] # every nth time we find a , insert a (where n = numColumns) count = 0 # track the number of 's processed idx = 0 # the index to start searching for the next while (count < numCells): idx = text.find("", idx) if count % numColumns == 0: text = text[:idx] + "" + text[idx:] idx += 4 # jump past the we inserted idx += 4 # jump past the we just found count += 1 # every nth time we find a , insert a (where n = numColumns) count = 0 # track the number of 's processed idx = 0 # the index to start searching for the next while (count < numCells): idx = text.find("", idx) if count % numColumns == numColumns - 1 : text = text[:idx+5] + "" + text[idx+5:] idx += 4 # jump past the we inserted idx += 4 # jump past the we just found count += 1 # fix whitespace issues # - remove whitespace after newlines # - get rid of newlines # - remove whitespace after 's idx = text.find("\n", 0) while (idx>0): text = text[:idx + 1] + text[idx + 1:].strip() # add 1 to skip the \n we just found idx = text.find("\n", idx + 1) # add 1 to skip the \n we just found text = text.replace("\n", " ") idx = text.find("", 0) while (idx>0): text = text[:idx + 4] + text[idx + 4:].strip() # add 4 to skip the we just found idx = text.find("", idx + 4) # add 4 to skip the we just found return text # Converts xref and eref tags to wiki links. def __convertLinks(self, text): #text = re.sub(r'([^<]*)', # r'[[\1 ' + self.specVersion + r' | \2]]', text) text = re.sub(r'((?s)[^<]*)', r'[[\1 ' + self.specVersion + r' | \2]]', text) text = re.sub(r'((?s)[^<]*)', r'[\1 \2]', text) return text # Converts the spec representation of a code block to wikified text def __convertCode(self, text): text = re.sub(r'
\n((?s).*)
', r'\1', text) text = re.sub(r'((?s).*)', r'', text) text = re.sub(r'\n((?s).*)', r'\1', text) return text # Converts the given spec fields into text for a wiki page # # param specFields a minidom.Node containing field info in spec format # returns a string containing wiki markup for the fields def convertFields(self, specFields): # Get the name of the class for the section header title = specFields.getAttribute("title") wikitext = "==%s==\n" % title # Get the high level description from the first child text = specFields.getElementsByTagName("t")[0].toxml() text = self.__convertLinks(text) text = self.__removeWhitespace(text) wikitext += text.strip() + "\n\n" # Iterate over the subsections of 'Field Details' for node in specFields.getElementsByTagName("section"): if not node.parentNode.isSameNode(specFields): continue if node.getAttribute("title") == "Field Details": for fieldNode in node.getElementsByTagName("section"): wikitext += "=== %s ===\n" % fieldNode.getAttribute('anchor') text = fieldNode.toxml() text = re.sub(r'', r'', text) text = re.sub(r'
', r'', text) text = re.sub(r'.*', r'', text, 1) text = self.__convertLinks(text) text = self.__removeWhitespace(text) + "\n" wikitext += ":" + text return wikitext # Takes out all whitespace on each line def __removeWhitespace(self, text): text = text.strip() text = text.replace("","").replace("","") lines = text.split("\n") toReturn = "" for line in lines: line = line.strip() if line.startswith("Description:"): line = line[13:].strip() toReturn += line + " " return toReturn.strip() def __removeLeadingWhitespace(self, wikiString): toReturn = '' lines = wikiString.split('\n') for line in lines: toReturn += line.strip() + '\n' return toReturn