configurationengine/source/testautomation/testautomation/compare_xml.py
author terytkon
Thu, 11 Mar 2010 17:04:37 +0200
changeset 0 2e8eeb919028
permissions -rw-r--r--
Adding EPL version of configurationengine.
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
0
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
     1
#
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
     2
# Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
     3
# All rights reserved.
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
     4
# This component and the accompanying materials are made available
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
     5
# under the terms of "Eclipse Public License v1.0"
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
     6
# which accompanies this distribution, and is available
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
     7
# at the URL "http://www.eclipse.org/legal/epl-v10.html".
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
     8
#
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
     9
# Initial Contributors:
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
    10
# Nokia Corporation - initial contribution.
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
    11
#
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
    12
# Contributors:
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
    13
#
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
    14
# Description:
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
    15
#
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
    16
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
    17
import sys
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
    18
import xml.etree.ElementTree as ElementTree
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
    19
import unittest
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
    20
import traceback
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
    21
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
    22
def compare_xml_documents(data1, data2, **kwargs):
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
    23
    """
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
    24
    Compare two XML documents for equality.
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
    25
    @param data1: The raw byte data of the first XML document as a string.
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
    26
    @param data2: The raw byte data of the second XML document as a string.
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
    27
    
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
    28
    Keyword arguments:
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
    29
    @param check_encoding: If True, the encoding of the documents is checked to be the same.
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
    30
    @param ignore_namespace: If True, XML namespaces are ignored in the comparison.
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
    31
    @param ignored_empty_tags: List of tags that will be ignored in the comparison if empty,
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
    32
        i.e. if the tags is empty on one side and does not exist on the other.
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
    33
    @param debug_stream: If not None, the stream where debug messages are printed.
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
    34
    
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
    35
    @return: True if the documents are equal, False if not.
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
    36
    """
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
    37
    
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
    38
    check_encoding = kwargs.get('check_encoding', False)
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
    39
    ignore_namespaces = kwargs.get('ignore_namespaces', False)
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
    40
    debug_stream = kwargs.get('debug_stream', None)
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
    41
    ignored_empty_tags = kwargs.get('ignored_empty_tags', [])
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
    42
    
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
    43
    if data1 == data2:
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
    44
        if debug_stream: print >>debug_stream, "Raw byte data equal"
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
    45
        return True
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
    46
    
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
    47
    if check_encoding:
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
    48
        enc1 = _get_xml_encoding(data1)
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
    49
        enc2 = _get_xml_encoding(data2)
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
    50
        if enc1.lower() != enc2.lower():
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
    51
            if debug_stream: print >>debug_stream, "XML encoding is not the same (%s vs. %s)" % (repr(enc1), repr(enc2))
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
    52
            return False
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
    53
    
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
    54
    try:
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
    55
        et1 = ElementTree.fromstring(data1)
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
    56
    except Exception:
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
    57
        if debug_stream: print >>debug_stream, "Failure when parsing data1: %s" % traceback.format_exc()
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
    58
        return False
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
    59
    
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
    60
    try:
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
    61
        et2 = ElementTree.fromstring(data2)
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
    62
    except Exception:
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
    63
        if debug_stream: print >>debug_stream, "Failure when parsing data2: %s" % traceback.format_exc()
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
    64
        return False
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
    65
    
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
    66
    return _xml_elements_equal(et1, et2, ignore_namespaces, debug_stream, '', ignored_empty_tags)
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
    67
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
    68
def _xml_elements_equal(elem1, elem2, ignore_namespaces, debug_stream, parent_path, ignored_empty_tags):
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
    69
    ds = debug_stream
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
    70
    
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
    71
    elem1_tag = _get_tag(elem1, ignore_namespaces)
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
    72
    elem2_tag = _get_tag(elem2, ignore_namespaces)
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
    73
    
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
    74
    full_path1 = parent_path + '/' + elem1_tag
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
    75
    full_path2 = parent_path + '/' + elem2_tag
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
    76
    if ds and parent_path == '':
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
    77
        print >>ds, "Comparing '%s' vs. '%s'" % (full_path1, full_path2)
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
    78
    
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
    79
    if elem1_tag != elem2_tag:
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
    80
        if ds and parent_path == '':
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
    81
            print >>ds, "Tags don't match"
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
    82
        return False
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
    83
    
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
    84
    def strip_string(data):
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
    85
        if data == None:    return data
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
    86
        else:               return data.strip(' \n\r\t')
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
    87
    text1 = strip_string(elem1.text)
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
    88
    text2 = strip_string(elem2.text)
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
    89
    if text1 != text2:
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
    90
        if ds and parent_path == '':
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
    91
            print >>ds, "Element text %s does not match %s" % (repr(text1), repr(text2))
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
    92
        return False
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
    93
    
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
    94
    def strip_namespace_attrs(attrib):
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
    95
        if not ignore_namespaces:
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
    96
            return attrib
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
    97
        else:
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
    98
            # Strip all attributes with a namespace if namespace are ignored
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
    99
            result = {}
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   100
            for key, value in attrib.iteritems():
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   101
                if '{' not in key:
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   102
                    result[key] = value
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   103
            return result
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   104
    attrs1 = strip_namespace_attrs(elem1.attrib)
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   105
    attrs2 = strip_namespace_attrs(elem2.attrib)
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   106
    if attrs1 != attrs2:
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   107
        if ds and parent_path == '':
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   108
            print >>ds, "Element attributes don't match (%s vs. %s)" % (repr(attrs1), repr(attrs2))
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   109
        return False
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   110
    
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   111
    # Remove ignored empty sub-elements before comparing the sub-elems
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   112
    subelems1 = elem1.getchildren()
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   113
    subelems2 = elem2.getchildren()
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   114
    _remove_ignored_empty_subelems(subelems1, elem2.getchildren(), full_path1, ignore_namespaces, ignored_empty_tags, ds)
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   115
    _remove_ignored_empty_subelems(subelems2, elem1.getchildren(), full_path1, ignore_namespaces, ignored_empty_tags, ds)
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   116
    
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   117
    # Compare sub-elements without caring about their document order
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   118
    # NOTE: This approach will not scale well for very large documents
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   119
    len1 = len(elem1.getchildren())
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   120
    len2 = len(elem2.getchildren())
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   121
    if len1 != len2:    return False
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   122
    if len1 == 0:       return True
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   123
    matched_subelems2 = []
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   124
    for subelem1 in subelems1:
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   125
        matched = False
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   126
        for subelem2 in subelems2:
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   127
            # Try to match the sub-element in elem2 only if it
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   128
            # has not been matched yet
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   129
            if id(subelem2) not in matched_subelems2:
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   130
                if _xml_elements_equal(subelem1, subelem2, ignore_namespaces, ds, full_path1, ignored_empty_tags):
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   131
                    matched = True
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   132
                    matched_subelems2.append(id(subelem2))
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   133
                    break
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   134
        if not matched:
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   135
            if ds:
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   136
                print >>ds, "No match found for element '%s' under '%s'." % (subelem1.tag, full_path1)
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   137
                print >>ds, "Element data:"
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   138
                print >>ds, ElementTree.tostring(subelem1)
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   139
            return False
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   140
    
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   141
    # Everything matched
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   142
    return True
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   143
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   144
def _remove_ignored_empty_subelems(subelems1, subelems2, parent_path, ignore_namespaces, ignored_empty_tags, debug_stream):
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   145
    """Remove ignored empty sub-elements from list subelems1."""
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   146
    ds = debug_stream
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   147
    if ds: print >>ds, "parent_path: %s" % parent_path
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   148
    removed = []
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   149
    for i, subelem1 in enumerate(subelems1):
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   150
        if len(subelem1.getchildren()) > 0:
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   151
            continue
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   152
        
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   153
        # See if the tag should be ignored if it doesn't exist on
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   154
        # the other side
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   155
        is_ignored = False
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   156
        for ignored_tag in ignored_empty_tags:
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   157
            if ds: print >>ds, "ignored_tag = %s, tag = %s" % (ignored_tag, parent_path + "/" + _get_tag(subelem1, ignore_namespaces))
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   158
            if ignored_tag == parent_path + "/" + _get_tag(subelem1, ignore_namespaces):
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   159
                is_ignored = True
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   160
                break
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   161
        if not is_ignored:
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   162
            continue
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   163
        
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   164
        # See if the tag exists on the other side
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   165
        found = False
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   166
        for subelem2 in subelems2:
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   167
            if _get_tag(subelem1, ignore_namespaces) == _get_tag(subelem2, ignore_namespaces):
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   168
                found = True
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   169
                break
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   170
        if not found:
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   171
            removed.append(i)
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   172
    
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   173
    # Sort and reverse the removed list so that deleting starts from the
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   174
    # end and the indices are correct throughout the operation
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   175
    removed.sort()
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   176
    removed = removed[::-1]
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   177
    if len(removed) >= 2:
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   178
        if removed[0] < removed[-1]:
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   179
            raise RuntimeError("Internal error: list in wrong order: %s" % removed)
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   180
    
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   181
    for i in removed:
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   182
        del subelems1[i]
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   183
        
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   184
def _get_tag(elem, ignore_namespaces):
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   185
    tag = elem.tag
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   186
    if ignore_namespaces:
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   187
        pos = tag.find('}')
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   188
        if pos >= 0:
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   189
            tag = tag[pos + 1:]
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   190
    return tag
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   191
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   192
def _get_xml_encoding(xml_data):
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   193
    encoding = 'UTF-8'
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   194
    if xml_data.startswith('\xFE\xFF') or xml_data.startswith('\xFF\xFE'):
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   195
        encoding = 'UTF-16'
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   196
    
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   197
    # Decode only up to the first 200 bytes (should be enough for the header)
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   198
    decoded_data = xml_data[:200].decode(encoding, 'ignore')
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   199
    if decoded_data.startswith('<?xml'):
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   200
        header = decoded_data[:decoded_data.find('?>') + 2]
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   201
        # E.g header = '<?xml version="1.0" encoding = 'UTF-8'?>'
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   202
        
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   203
        def get_substr(string, sought_data):
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   204
            pos = string.find(sought_data)
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   205
            if pos >= 0:    return string[pos + len(sought_data):]
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   206
            else:           return None
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   207
        
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   208
        x = get_substr(header, "encoding")
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   209
        if not x: return ''
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   210
        # E.g x = ' = 'UTF-8'?>'
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   211
        x = x.replace(' ', '').replace('\t', '')
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   212
        # E.g x = '='UTF-8'?>'
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   213
        sgl_quoted = get_substr(x, "='")
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   214
        dbl_quoted = get_substr(x, '="')
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   215
        # E.g sgl_quoted = 'UTF-8'?>'
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   216
        if sgl_quoted:      return sgl_quoted[:sgl_quoted.find("'")]
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   217
        elif dbl_quoted:    return dbl_quoted[:dbl_quoted.find('"')]
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   218
        
2e8eeb919028 Adding EPL version of configurationengine.
terytkon
parents:
diff changeset
   219
    return ''