Package qm :: Module xmlutil
[hide private]
[frames] | no frames]

Source Code for Module qm.xmlutil

  1  ######################################################################## 
  2  # 
  3  # File:   xmlutil.py 
  4  # Author: Alex Samuel 
  5  # Date:   2001-03-18 
  6  # 
  7  # Contents: 
  8  #   Miscellaneous XML-related functions. 
  9  # 
 10  # Copyright (c) 2001, 2002 by CodeSourcery, LLC.  All rights reserved.  
 11  # 
 12  # For license terms see the file COPYING. 
 13  # 
 14  ######################################################################## 
 15   
 16  ######################################################################## 
 17  # imports 
 18  ######################################################################## 
 19   
 20  import os 
 21  import qm 
 22  import re 
 23  import xml.dom 
 24  import xml.dom.minidom 
 25   
 26  ######################################################################## 
 27  # functions 
 28  ######################################################################## 
 29   
30 -def make_public_id(name):
31 """Return a public ID for the DTD with the given 'name'. 32 33 'name' -- The name of the DTD. 34 35 returns -- A public ID for the DTD.""" 36 37 return "-//QM/%s/%s//EN" % (qm.version, name)
38 39
40 -def make_system_id(name):
41 """Return a system ID for the DTD with the given 'name'. 42 43 'name' -- The name of the DTD, as a relative UNIX path. 44 45 returns -- A URL for the DTD.""" 46 47 return "http://www.codesourcery.com/qm/dtds/%s/%s" % (qm.version, name)
48 49
50 -def load_xml_file(path):
51 """Return a DOM document loaded from the XML file 'path'.""" 52 53 # Open the file. 54 file = open(path, "r") 55 return load_xml(file)
56 57
58 -def load_xml(file):
59 """Return a DOM document loaded from the XML file object 'file'. 60 61 'file' -- A file object, opened for reading. 62 63 returns -- The DOM document contained in 'file'. 64 65 This function closes 'file', whether or not reading the document was 66 successful.""" 67 68 try: 69 document = xml.dom.minidom.parse(file) 70 finally: 71 file.close() 72 return document
73 74
75 -def get_dom_text(node):
76 """Return the text contained in DOM 'node'. 77 78 'node' -- A DOM element node. 79 80 prerequisites -- 'node' is an element node with exactly one child, 81 which is a text node.""" 82 83 assert node.nodeType == xml.dom.Node.ELEMENT_NODE 84 # Normalize the node so that multiple TEXT_NODEs are collapsed into 85 # a single node. 86 node.normalize() 87 # If there are no children, the string is empty. 88 if len(node.childNodes) == 0: 89 return "" 90 # If there is a child, there should be only one. 91 if len(node.childNodes) != 1: 92 raise QMException, "Invalid XML text node." 93 child = node.childNodes[0] 94 if child.nodeType != xml.dom.Node.TEXT_NODE: 95 raise QMException, "Invalid XML text node." 96 return child.data
97 98
99 -def child_tag_predicate(child_tag):
100 """Return a predicate function for finding element nodes by tag. 101 102 returns -- A predicate function that takes a node as its argument 103 and returns true if the node is an element node whose tag is 104 'child_tag'.""" 105 106 return lambda node, tag=child_tag: \ 107 node.nodeType == xml.dom.Node.ELEMENT_NODE \ 108 and node.tagName == tag
109 110
111 -def get_child(node, child_tag):
112 """Return the child element node of 'node' whose tag is 'child_tag'. 113 114 'node' -- A DOM node. It must have exactly one element child with 115 the tag 'child_tag'. 116 117 'child_tag' -- The desired element tag. 118 119 returns -- A child DOM node of 'node'. 120 121 raises -- 'KeyError' if 'node' has no element child with tag 122 'child_tag', or more than one.. """ 123 124 matching_children = \ 125 filter(child_tag_predicate(child_tag), node.childNodes) 126 if len(matching_children) != 1: 127 raise KeyError, child_tag 128 return matching_children[0]
129 130
131 -def get_child_text(node, child_tag, default=None):
132 """Return the text contained in a child of DOM 'node'. 133 134 'child_tag' -- The tag of the child node whose text is to be 135 retrieved. 136 137 'default' -- If 'node' has no child element with tag 'child_tag', 138 returns 'default', unless 'default' is 'None'. 139 140 raises -- 'KeyError' if 'default' is 'None' and 'node' has no child 141 element with tag 'child_tag'.""" 142 143 try: 144 return get_dom_text(get_child(node, child_tag)) 145 except KeyError: 146 if default is not None: 147 return default 148 else: 149 raise
150 151
152 -def get_child_texts(node, child_tag):
153 """Return a sequence of text contents of children. 154 155 'node' -- A DOM node. 156 157 returns -- The list containing all child nodes of 'node' which have 158 tag 'child_tag'. Each child must have exactly one child of its own, 159 which must be a text node.""" 160 161 return map(get_dom_text, node.getElementsByTagName(child_tag))
162 163
164 -def create_dom_text_element(document, tag, text):
165 """Return a DOM element containing a single text node. 166 167 'document' -- The containing DOM document. 168 169 'tag' -- The element tag. 170 171 'text' -- The text contents of the text node.""" 172 173 element = document.createElement(tag) 174 if text != "": 175 text_node = document.createTextNode(text) 176 element.appendChild(text_node) 177 else: 178 # Don't create a child node in this case. For some reason, it 179 # gets written out with an extraneous newline, and therefore 180 # when the text is read in, its no longer an empty string. 181 pass 182 return element
183 184 185 __dom_implementation = xml.dom.minidom.getDOMImplementation() 186
187 -def create_dom_document(public_id, document_element_tag):
188 """Create a DOM document. 189 190 'public_id' -- The (partial) public ID for the DTD. 191 192 'document_element_tag' -- The tag of the main document element. 193 194 returns -- A DOM document node.""" 195 196 public_id = make_public_id(public_id) 197 system_id = make_system_id(public_id.lower() + ".dtd") 198 # Create the document type for the XML document. 199 document_type = __dom_implementation.createDocumentType( 200 qualifiedName=document_element_tag, 201 publicId=public_id, 202 systemId=system_id 203 ) 204 # Create a new DOM document. 205 document = __dom_implementation.\ 206 createDocument(namespaceURI=None, 207 qualifiedName=document_element_tag, 208 doctype=document_type) 209 return document
210 211 212 __hyphen_regex = re.compile("(--+)") 213
214 -def __hyphen_replacement(match):
215 return "-" + " -" * (len(match.group(0)) - 1)
216 217
218 -def sanitize_text_for_comment(text):
219 """Return 'text' modified so that it is valid for an XML comment.""" 220 221 # A comment cannot contain two or more hyphens in a row. 222 text = __hyphen_regex.sub(__hyphen_replacement, text) 223 224 return text
225 226 227 ######################################################################## 228 # Local Variables: 229 # mode: python 230 # indent-tabs-mode: nil 231 # fill-column: 72 232 # End: 233