"Fossies" - the Fresh Open Source Software Archive

Member "Atom/resources/app/apm/node_modules/node-gyp/gyp/pylib/gyp/easy_xml.py" (7 Feb 2017, 4945 Bytes) of archive /windows/misc/atom-windows.zip:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Python source code syntax highlighting (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file.

    1 # Copyright (c) 2011 Google Inc. All rights reserved.
    2 # Use of this source code is governed by a BSD-style license that can be
    3 # found in the LICENSE file.
    4 
    5 import re
    6 import os
    7 
    8 
    9 def XmlToString(content, encoding='utf-8', pretty=False):
   10   """ Writes the XML content to disk, touching the file only if it has changed.
   11 
   12   Visual Studio files have a lot of pre-defined structures.  This function makes
   13   it easy to represent these structures as Python data structures, instead of
   14   having to create a lot of function calls.
   15 
   16   Each XML element of the content is represented as a list composed of:
   17   1. The name of the element, a string,
   18   2. The attributes of the element, a dictionary (optional), and
   19   3+. The content of the element, if any.  Strings are simple text nodes and
   20       lists are child elements.
   21 
   22   Example 1:
   23       <test/>
   24   becomes
   25       ['test']
   26 
   27   Example 2:
   28       <myelement a='value1' b='value2'>
   29          <childtype>This is</childtype>
   30          <childtype>it!</childtype>
   31       </myelement>
   32 
   33   becomes
   34       ['myelement', {'a':'value1', 'b':'value2'},
   35          ['childtype', 'This is'],
   36          ['childtype', 'it!'],
   37       ]
   38 
   39   Args:
   40     content:  The structured content to be converted.
   41     encoding: The encoding to report on the first XML line.
   42     pretty: True if we want pretty printing with indents and new lines.
   43 
   44   Returns:
   45     The XML content as a string.
   46   """
   47   # We create a huge list of all the elements of the file.
   48   xml_parts = ['<?xml version="1.0" encoding="%s"?>' % encoding]
   49   if pretty:
   50     xml_parts.append('\n')
   51   _ConstructContentList(xml_parts, content, pretty)
   52 
   53   # Convert it to a string
   54   return ''.join(xml_parts)
   55 
   56 
   57 def _ConstructContentList(xml_parts, specification, pretty, level=0):
   58   """ Appends the XML parts corresponding to the specification.
   59 
   60   Args:
   61     xml_parts: A list of XML parts to be appended to.
   62     specification:  The specification of the element.  See EasyXml docs.
   63     pretty: True if we want pretty printing with indents and new lines.
   64     level: Indentation level.
   65   """
   66   # The first item in a specification is the name of the element.
   67   if pretty:
   68     indentation = '  ' * level
   69     new_line = '\n'
   70   else:
   71     indentation = ''
   72     new_line = ''
   73   name = specification[0]
   74   if not isinstance(name, str):
   75     raise Exception('The first item of an EasyXml specification should be '
   76                     'a string.  Specification was ' + str(specification))
   77   xml_parts.append(indentation + '<' + name)
   78 
   79   # Optionally in second position is a dictionary of the attributes.
   80   rest = specification[1:]
   81   if rest and isinstance(rest[0], dict):
   82     for at, val in sorted(rest[0].iteritems()):
   83       xml_parts.append(' %s="%s"' % (at, _XmlEscape(val, attr=True)))
   84     rest = rest[1:]
   85   if rest:
   86     xml_parts.append('>')
   87     all_strings = reduce(lambda x, y: x and isinstance(y, str), rest, True)
   88     multi_line = not all_strings
   89     if multi_line and new_line:
   90       xml_parts.append(new_line)
   91     for child_spec in rest:
   92       # If it's a string, append a text node.
   93       # Otherwise recurse over that child definition
   94       if isinstance(child_spec, str):
   95        xml_parts.append(_XmlEscape(child_spec))
   96       else:
   97         _ConstructContentList(xml_parts, child_spec, pretty, level + 1)
   98     if multi_line and indentation:
   99       xml_parts.append(indentation)
  100     xml_parts.append('</%s>%s' % (name, new_line))
  101   else:
  102     xml_parts.append('/>%s' % new_line)
  103 
  104 
  105 def WriteXmlIfChanged(content, path, encoding='utf-8', pretty=False,
  106                       win32=False):
  107   """ Writes the XML content to disk, touching the file only if it has changed.
  108 
  109   Args:
  110     content:  The structured content to be written.
  111     path: Location of the file.
  112     encoding: The encoding to report on the first line of the XML file.
  113     pretty: True if we want pretty printing with indents and new lines.
  114   """
  115   xml_string = XmlToString(content, encoding, pretty)
  116   if win32 and os.linesep != '\r\n':
  117     xml_string = xml_string.replace('\n', '\r\n')
  118     
  119   try:
  120     xml_string = xml_string.encode(encoding)
  121   except Exception:
  122     xml_string = unicode(xml_string, 'latin-1').encode(encoding)
  123 
  124   # Get the old content
  125   try:
  126     f = open(path, 'r')
  127     existing = f.read()
  128     f.close()
  129   except:
  130     existing = None
  131 
  132   # It has changed, write it
  133   if existing != xml_string:
  134     f = open(path, 'w')
  135     f.write(xml_string)
  136     f.close()
  137 
  138 
  139 _xml_escape_map = {
  140     '"': '&quot;',
  141     "'": '&apos;',
  142     '<': '&lt;',
  143     '>': '&gt;',
  144     '&': '&amp;',
  145     '\n': '&#xA;',
  146     '\r': '&#xD;',
  147 }
  148 
  149 
  150 _xml_escape_re = re.compile(
  151     "(%s)" % "|".join(map(re.escape, _xml_escape_map.keys())))
  152 
  153 
  154 def _XmlEscape(value, attr=False):
  155   """ Escape a string for inclusion in XML."""
  156   def replace(match):
  157     m = match.string[match.start() : match.end()]
  158     # don't replace single quotes in attrs
  159     if attr and m == "'":
  160       return m
  161     return _xml_escape_map[m]
  162   return _xml_escape_re.sub(replace, value)