195640e3a20adea634b4df4ccf8c93f411184c438joi@chromium.org#!/usr/bin/env python
295640e3a20adea634b4df4ccf8c93f411184c438joi@chromium.org# Copyright (c) 2012 The Chromium Authors. All rights reserved.
301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org# Use of this source code is governed by a BSD-style license that can be
401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org# found in the LICENSE file.
501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org
601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org
701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.orgfrom grit.format.policy_templates.writers import template_writer
801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org
901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org
1001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.orgclass XMLFormattedWriter(template_writer.TemplateWriter):
1101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org  '''Helper class for generating XML-based templates.
1201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org  '''
1301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org
1401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org  def AddElement(self, parent, name, attrs=None, text=None):
1501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org    '''
1601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org    Adds a new XML Element as a child to an existing element or the Document.
1701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org
1801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org    Args:
1901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org      parent: An XML element or the document, where the new element will be
2001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org        added.
2101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org      name: The name of the new element.
2201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org      attrs: A dictionary of the attributes' names and values for the new
2301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org        element.
2401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org      text: Text content for the new element.
2501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org
2601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org    Returns:
2701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org      The created new element.
2801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org    '''
2901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org    if attrs == None:
3001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org      attrs = {}
3101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org
3201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org    doc = parent.ownerDocument
3301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org    element = doc.createElement(name)
3401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org    for key, value in attrs.iteritems():
3501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org      element.setAttribute(key, value)
3601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org    if text:
3701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org      element.appendChild(doc.createTextNode(text))
3801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org    parent.appendChild(element)
3901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org    return element
4001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org
4101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org  def AddText(self, parent, text):
4201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org    '''Adds text to a parent node.
4301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org    '''
4401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org    doc = parent.ownerDocument
4501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org    parent.appendChild(doc.createTextNode(text))
4601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org
4701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org  def AddAttribute(self, parent, name, value):
4801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org    '''Adds a new attribute to the parent Element. If an attribute with the
4901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org    given name already exists then it will be replaced.
5001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org    '''
5101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org    doc = parent.ownerDocument
5201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org    attribute = doc.createAttribute(name)
5301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org    attribute.value = value
5401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org    parent.setAttributeNode(attribute)
5501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org
566fb6d62a2a05b7a7c268cc4e6bf0452e376e1990joaodasilva@chromium.org  def AddComment(self, parent, comment):
576fb6d62a2a05b7a7c268cc4e6bf0452e376e1990joaodasilva@chromium.org    '''Adds a comment node.'''
586fb6d62a2a05b7a7c268cc4e6bf0452e376e1990joaodasilva@chromium.org    parent.appendChild(parent.ownerDocument.createComment(comment))
596fb6d62a2a05b7a7c268cc4e6bf0452e376e1990joaodasilva@chromium.org
606fb6d62a2a05b7a7c268cc4e6bf0452e376e1990joaodasilva@chromium.org  def ToPrettyXml(self, doc, **kwargs):
6101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org    # return doc.toprettyxml(indent='  ')
6201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org    # The above pretty-printer does not print the doctype and adds spaces
6301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org    # around texts, e.g.:
6401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org    #  <string>
6501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org    #    value of the string
6601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org    #  </string>
6701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org    # This is problematic both for the OSX Workgroup Manager (plist files) and
6801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org    # the Windows Group Policy Editor (admx files). What they need instead:
6901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org    #  <string>value of string</string>
7001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org    # So we use the poor man's pretty printer here. It assumes that there are
7101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org    # no mixed-content nodes.
7201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org    # Get all the XML content in a one-line string.
736fb6d62a2a05b7a7c268cc4e6bf0452e376e1990joaodasilva@chromium.org    xml = doc.toxml(**kwargs)
7401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org    # Determine where the line breaks will be. (They will only be between tags.)
7501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org    lines = xml[1:len(xml) - 1].split('><')
7601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org    indent = ''
7701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org    res = ''
7801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org    # Determine indent for each line.
79b9161407f737461b5db16a29782f8a31d19e602dbenrg@chromium.org    for i, line in enumerate(lines):
8001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org      if line[0] == '/':
8101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org        # If the current line starts with a closing tag, decrease indent before
8201b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org        # printing.
8301b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org        indent = indent[2:]
8401b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org      lines[i] = indent + '<' + line + '>'
8501b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org      if (line[0] not in ['/', '?', '!'] and '</' not in line and
8601b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org          line[len(line) - 1] != '/'):
8701b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org        # If the current line starts with an opening tag and does not conatin a
8801b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org        # closing tag, increase indent after the line is printed.
8901b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org        indent += '  '
9001b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org    # Reconstruct XML text from the lines.
9101b3bc768461bd303bff39f8cd1663682254e407joi@chromium.org    return '\n'.join(lines)
92