source: trip-planner-front/node_modules/node-gyp/gyp/pylib/gyp/easy_xml.py

Last change on this file was 6a3a178, checked in by Ema <ema_spirova@…>, 3 years ago

initial commit

  • Property mode set to 100644
File size: 5.1 KB
Line 
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
5import re
6import os
7import locale
8from functools import reduce
9
10
11def XmlToString(content, encoding="utf-8", pretty=False):
12 """ Writes the XML content to disk, touching the file only if it has changed.
13
14 Visual Studio files have a lot of pre-defined structures. This function makes
15 it easy to represent these structures as Python data structures, instead of
16 having to create a lot of function calls.
17
18 Each XML element of the content is represented as a list composed of:
19 1. The name of the element, a string,
20 2. The attributes of the element, a dictionary (optional), and
21 3+. The content of the element, if any. Strings are simple text nodes and
22 lists are child elements.
23
24 Example 1:
25 <test/>
26 becomes
27 ['test']
28
29 Example 2:
30 <myelement a='value1' b='value2'>
31 <childtype>This is</childtype>
32 <childtype>it!</childtype>
33 </myelement>
34
35 becomes
36 ['myelement', {'a':'value1', 'b':'value2'},
37 ['childtype', 'This is'],
38 ['childtype', 'it!'],
39 ]
40
41 Args:
42 content: The structured content to be converted.
43 encoding: The encoding to report on the first XML line.
44 pretty: True if we want pretty printing with indents and new lines.
45
46 Returns:
47 The XML content as a string.
48 """
49 # We create a huge list of all the elements of the file.
50 xml_parts = ['<?xml version="1.0" encoding="%s"?>' % encoding]
51 if pretty:
52 xml_parts.append("\n")
53 _ConstructContentList(xml_parts, content, pretty)
54
55 # Convert it to a string
56 return "".join(xml_parts)
57
58
59def _ConstructContentList(xml_parts, specification, pretty, level=0):
60 """ Appends the XML parts corresponding to the specification.
61
62 Args:
63 xml_parts: A list of XML parts to be appended to.
64 specification: The specification of the element. See EasyXml docs.
65 pretty: True if we want pretty printing with indents and new lines.
66 level: Indentation level.
67 """
68 # The first item in a specification is the name of the element.
69 if pretty:
70 indentation = " " * level
71 new_line = "\n"
72 else:
73 indentation = ""
74 new_line = ""
75 name = specification[0]
76 if not isinstance(name, str):
77 raise Exception(
78 "The first item of an EasyXml specification should be "
79 "a string. Specification was " + str(specification)
80 )
81 xml_parts.append(indentation + "<" + name)
82
83 # Optionally in second position is a dictionary of the attributes.
84 rest = specification[1:]
85 if rest and isinstance(rest[0], dict):
86 for at, val in sorted(rest[0].items()):
87 xml_parts.append(' %s="%s"' % (at, _XmlEscape(val, attr=True)))
88 rest = rest[1:]
89 if rest:
90 xml_parts.append(">")
91 all_strings = reduce(lambda x, y: x and isinstance(y, str), rest, True)
92 multi_line = not all_strings
93 if multi_line and new_line:
94 xml_parts.append(new_line)
95 for child_spec in rest:
96 # If it's a string, append a text node.
97 # Otherwise recurse over that child definition
98 if isinstance(child_spec, str):
99 xml_parts.append(_XmlEscape(child_spec))
100 else:
101 _ConstructContentList(xml_parts, child_spec, pretty, level + 1)
102 if multi_line and indentation:
103 xml_parts.append(indentation)
104 xml_parts.append("</%s>%s" % (name, new_line))
105 else:
106 xml_parts.append("/>%s" % new_line)
107
108
109def WriteXmlIfChanged(content, path, encoding="utf-8", pretty=False, win32=False):
110 """ Writes the XML content to disk, touching the file only if it has changed.
111
112 Args:
113 content: The structured content to be written.
114 path: Location of the file.
115 encoding: The encoding to report on the first line of the XML file.
116 pretty: True if we want pretty printing with indents and new lines.
117 """
118 xml_string = XmlToString(content, encoding, pretty)
119 if win32 and os.linesep != "\r\n":
120 xml_string = xml_string.replace("\n", "\r\n")
121
122 default_encoding = locale.getdefaultlocale()[1]
123 if default_encoding and default_encoding.upper() != encoding.upper():
124 xml_string = xml_string.encode(encoding)
125
126 # Get the old content
127 try:
128 with open(path, "r") as file:
129 existing = file.read()
130 except IOError:
131 existing = None
132
133 # It has changed, write it
134 if existing != xml_string:
135 with open(path, "wb") as file:
136 file.write(xml_string)
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("(%s)" % "|".join(map(re.escape, _xml_escape_map.keys())))
151
152
153def _XmlEscape(value, attr=False):
154 """ Escape a string for inclusion in XML."""
155
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
163 return _xml_escape_re.sub(replace, value)
Note: See TracBrowser for help on using the repository browser.