1## @file
2# This is an XML API that uses a syntax similar to XPath, but it is written in
3# standard python so that no extra python packages are required to use it.
4#
5# Copyright (c) 2011 - 2014, Intel Corporation. All rights reserved.<BR>
6#
7# This program and the accompanying materials are licensed and made available
8# under the terms and conditions of the BSD License which accompanies this
9# distribution. The full text of the license may be found at
10# http://opensource.org/licenses/bsd-license.php
11#
12# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
14#
15
16'''
17XmlRoutines
18'''
19
20##
21# Import Modules
22#
23import xml.dom.minidom
24import re
25import codecs
26from Logger.ToolError import PARSER_ERROR
27import Logger.Log as Logger
28
29## Create a element of XML
30#
31# @param Name
32# @param String
33# @param NodeList
34# @param AttributeList
35#
36def CreateXmlElement(Name, String, NodeList, AttributeList):
37    Doc = xml.dom.minidom.Document()
38    Element = Doc.createElement(Name)
39    if String != '' and String != None:
40        Element.appendChild(Doc.createTextNode(String))
41
42    for Item in NodeList:
43        if type(Item) == type([]):
44            Key = Item[0]
45            Value = Item[1]
46            if Key != '' and Key != None and Value != '' and Value != None:
47                Node = Doc.createElement(Key)
48                Node.appendChild(Doc.createTextNode(Value))
49                Element.appendChild(Node)
50        else:
51            Element.appendChild(Item)
52    for Item in AttributeList:
53        Key = Item[0]
54        Value = Item[1]
55        if Key != '' and Key != None and Value != '' and Value != None:
56            Element.setAttribute(Key, Value)
57
58    return Element
59
60## Get a list of XML nodes using XPath style syntax.
61#
62# Return a list of XML DOM nodes from the root Dom specified by XPath String.
63# If the input Dom or String is not valid, then an empty list is returned.
64#
65# @param  Dom                The root XML DOM node.
66# @param  String             A XPath style path.
67#
68def XmlList(Dom, String):
69    if String == None or String == "" or Dom == None or Dom == "":
70        return []
71    if Dom.nodeType == Dom.DOCUMENT_NODE:
72        Dom = Dom.documentElement
73    if String[0] == "/":
74        String = String[1:]
75    TagList = String.split('/')
76    Nodes = [Dom]
77    Index = 0
78    End = len(TagList) - 1
79    while Index <= End:
80        ChildNodes = []
81        for Node in Nodes:
82            if Node.nodeType == Node.ELEMENT_NODE and Node.tagName == \
83            TagList[Index]:
84                if Index < End:
85                    ChildNodes.extend(Node.childNodes)
86                else:
87                    ChildNodes.append(Node)
88        Nodes = ChildNodes
89        ChildNodes = []
90        Index += 1
91
92    return Nodes
93
94
95## Get a single XML node using XPath style syntax.
96#
97# Return a single XML DOM node from the root Dom specified by XPath String.
98# If the input Dom or String is not valid, then an empty string is returned.
99#
100# @param  Dom                The root XML DOM node.
101# @param  String             A XPath style path.
102#
103def XmlNode(Dom, String):
104    if String == None or String == ""  or Dom == None or Dom == "":
105        return None
106    if Dom.nodeType == Dom.DOCUMENT_NODE:
107        Dom = Dom.documentElement
108    if String[0] == "/":
109        String = String[1:]
110    TagList = String.split('/')
111    Index = 0
112    End = len(TagList) - 1
113    ChildNodes = [Dom]
114    while Index <= End:
115        for Node in ChildNodes:
116            if Node.nodeType == Node.ELEMENT_NODE and \
117               Node.tagName == TagList[Index]:
118                if Index < End:
119                    ChildNodes = Node.childNodes
120                else:
121                    return Node
122                break
123        Index += 1
124    return None
125
126
127## Get a single XML element using XPath style syntax.
128#
129# Return a single XML element from the root Dom specified by XPath String.
130# If the input Dom or String is not valid, then an empty string is returned.
131#
132# @param  Dom                The root XML DOM object.
133# @param  Strin              A XPath style path.
134#
135def XmlElement(Dom, String):
136    try:
137        return XmlNode(Dom, String).firstChild.data.strip()
138    except BaseException:
139        return ""
140
141## Get a single XML element using XPath style syntax.
142#
143# Similar with XmlElement, but do not strip all the leading and tailing space
144# and newline, instead just remove the newline and spaces introduced by
145# toprettyxml()
146#
147# @param  Dom                The root XML DOM object.
148# @param  Strin              A XPath style path.
149#
150def XmlElement2(Dom, String):
151    try:
152        HelpStr = XmlNode(Dom, String).firstChild.data
153        gRemovePrettyRe = re.compile(r"""(?:(\n *)  )(.*)\1""", re.DOTALL)
154        HelpStr = re.sub(gRemovePrettyRe, r"\2", HelpStr)
155        return HelpStr
156    except BaseException:
157        return ""
158
159
160## Get a single XML element of the current node.
161#
162# Return a single XML element specified by the current root Dom.
163# If the input Dom is not valid, then an empty string is returned.
164#
165# @param  Dom                The root XML DOM object.
166#
167def XmlElementData(Dom):
168    try:
169        return Dom.firstChild.data.strip()
170    except BaseException:
171        return ""
172
173
174## Get a list of XML elements using XPath style syntax.
175#
176# Return a list of XML elements from the root Dom specified by XPath String.
177# If the input Dom or String is not valid, then an empty list is returned.
178#
179# @param  Dom                The root XML DOM object.
180# @param  String             A XPath style path.
181#
182def XmlElementList(Dom, String):
183    return map(XmlElementData, XmlList(Dom, String))
184
185
186## Get the XML attribute of the current node.
187#
188# Return a single XML attribute named Attribute from the current root Dom.
189# If the input Dom or Attribute is not valid, then an empty string is returned.
190#
191# @param  Dom                The root XML DOM object.
192# @param  Attribute          The name of Attribute.
193#
194def XmlAttribute(Dom, Attribute):
195    try:
196        return Dom.getAttribute(Attribute)
197    except BaseException:
198        return ''
199
200
201## Get the XML node name of the current node.
202#
203# Return a single XML node name from the current root Dom.
204# If the input Dom is not valid, then an empty string is returned.
205#
206# @param  Dom                The root XML DOM object.
207#
208def XmlNodeName(Dom):
209    try:
210        return Dom.nodeName.strip()
211    except BaseException:
212        return ''
213
214## Parse an XML file.
215#
216# Parse the input XML file named FileName and return a XML DOM it stands for.
217# If the input File is not a valid XML file, then an empty string is returned.
218#
219# @param  FileName           The XML file name.
220#
221def XmlParseFile(FileName):
222    try:
223        XmlFile = codecs.open(FileName, 'rb')
224        Dom = xml.dom.minidom.parse(XmlFile)
225        XmlFile.close()
226        return Dom
227    except BaseException, XExcept:
228        XmlFile.close()
229        Logger.Error('\nUPT', PARSER_ERROR, XExcept, File=FileName, RaiseError=True)
230