1#!/usr/bin/env python 2# Copyright (c) 2012 The Chromium Authors. All rights reserved. 3# Use of this source code is governed by a BSD-style license that can be 4# found in the LICENSE file. 5 6from writers import template_writer 7 8 9class XMLFormattedWriter(template_writer.TemplateWriter): 10 '''Helper class for generating XML-based templates. 11 ''' 12 13 def AddElement(self, parent, name, attrs=None, text=None): 14 ''' 15 Adds a new XML Element as a child to an existing element or the Document. 16 17 Args: 18 parent: An XML element or the document, where the new element will be 19 added. 20 name: The name of the new element. 21 attrs: A dictionary of the attributes' names and values for the new 22 element. 23 text: Text content for the new element. 24 25 Returns: 26 The created new element. 27 ''' 28 if attrs == None: 29 attrs = {} 30 31 doc = parent.ownerDocument 32 element = doc.createElement(name) 33 for key, value in sorted(attrs.iteritems()): 34 element.setAttribute(key, value) 35 if text: 36 element.appendChild(doc.createTextNode(text)) 37 parent.appendChild(element) 38 return element 39 40 def AddText(self, parent, text): 41 '''Adds text to a parent node. 42 ''' 43 doc = parent.ownerDocument 44 parent.appendChild(doc.createTextNode(text)) 45 46 def AddAttribute(self, parent, name, value): 47 '''Adds a new attribute to the parent Element. If an attribute with the 48 given name already exists then it will be replaced. 49 ''' 50 doc = parent.ownerDocument 51 attribute = doc.createAttribute(name) 52 attribute.value = value 53 parent.setAttributeNode(attribute) 54 55 def AddComment(self, parent, comment): 56 '''Adds a comment node.''' 57 parent.appendChild(parent.ownerDocument.createComment(comment)) 58 59 def ToPrettyXml(self, doc, **kwargs): 60 # return doc.toprettyxml(indent=' ') 61 # The above pretty-printer does not print the doctype and adds spaces 62 # around texts, e.g.: 63 # <string> 64 # value of the string 65 # </string> 66 # This is problematic both for the OSX Workgroup Manager (plist files) and 67 # the Windows Group Policy Editor (admx files). What they need instead: 68 # <string>value of string</string> 69 # So we use a hacky pretty printer here. It assumes that there are no 70 # mixed-content nodes. 71 # Get all the XML content in a one-line string. 72 xml = doc.toxml(**kwargs) 73 # Determine where the line breaks will be. (They will only be between tags.) 74 lines = xml[1:len(xml) - 1].split('><') 75 indent = '' 76 res = '' 77 # Determine indent for each line. 78 for i, line in enumerate(lines): 79 if line[0] == '/': 80 # If the current line starts with a closing tag, decrease indent before 81 # printing. 82 indent = indent[2:] 83 lines[i] = indent + '<' + line + '>' 84 if (line[0] not in ['/', '?', '!'] and '</' not in line and 85 line[len(line) - 1] != '/'): 86 # If the current line starts with an opening tag and does not conatin a 87 # closing tag, increase indent after the line is printed. 88 indent += ' ' 89 # Reconstruct XML text from the lines. 90 return '\n'.join(lines) 91