Add support for special char in volume metadata

Using special characters such as "&" in volume metadata caused SAX
parser to split text into multiple child nodes, as stated in the
specs for SAX parsers. In this case extract_text would return
'None' because text was return if there was exactly
one child node. Concatenating the values of child nodes accounts
for SAX parsers splitting contigous characters into
multiple chunks.

Change-Id: I3709789d33ff7b07eaeaf725f5183105443d0abc
Closes-Bug: #1268513
This commit is contained in:
Ryan McNair 2014-01-27 21:48:51 +00:00
parent f2cb3e8a84
commit 7d028b77a4
2 changed files with 29 additions and 4 deletions

View File

@ -290,11 +290,13 @@ class XMLDeserializer(TextDeserializer):
def extract_text(self, node):
"""Get the text field contained by the given node."""
if len(node.childNodes) == 1:
child = node.childNodes[0]
text = []
# Cannot assume entire text will be in a single child node because SAX
# parsers may split contiguous character data into multiple chunks
for child in node.childNodes:
if child.nodeType == child.TEXT_NODE:
return child.nodeValue
return ""
text.append(child.nodeValue)
return ''.join(text)
def find_attribute_or_element(self, parent, name):
"""Get an attribute value; fallback to an element if not found."""

View File

@ -245,6 +245,29 @@ class XMLDeserializerTest(test.TestCase):
self.assertEqual(deserializer.deserialize(xml), as_dict)
class MetadataXMLDeserializerTest(test.TestCase):
def test_xml_meta_parsing_special_character(self):
"""Test that when a SaxParser splits a string containing special
characters into multiple childNodes there are no issues extracting
the text.
"""
meta_xml_str = """
<metadata>
<meta key="key3">value&amp;3</meta>
<meta key="key2">value2</meta>
<meta key="key1">value1</meta>
</metadata>
""".strip()
meta_expected = {'key1': 'value1',
'key2': 'value2',
'key3': 'value&3'}
meta_deserializer = wsgi.MetadataXMLDeserializer()
document = wsgi.utils.safe_minidom_parse_string(meta_xml_str)
root_node = document.childNodes[0]
meta_extracted = meta_deserializer.extract_metadata(root_node)
self.assertEqual(meta_expected, meta_extracted)
class ResourceTest(test.TestCase):
def test_resource_call(self):
class Controller(object):