示例#1
0
    def test_render_with_provided_namespaces(self):
        serializer = XmlSerializer(pretty_print=True)
        namespaces = Namespaces()
        namespaces.add("urn:books", "burn")
        actual = serializer.render(self.books, namespaces)

        expected = (
            "<?xml version='1.0' encoding='UTF-8'?>\n"
            '<burn:books xmlns:burn="urn:books">\n'
            '  <book id="bk001" lang="en">\n'
            "    <author>Hightower, Kim</author>\n"
            "    <title>The First Book</title>\n"
            "    <genre>Fiction</genre>\n"
            "    <price>44.95</price>\n"
            "    <pub_date>2000-10-01</pub_date>\n"
            "    <review>An amazing story of nothing.</review>\n"
            "  </book>\n"
            '  <book id="bk002" lang="en">\n'
            "    <author>Nagata, Suanne</author>\n"
            "    <title>Becoming Somebody</title>\n"
            "    <genre>Biography</genre>\n"
            "    <review>A masterpiece of the fine art of gossiping.</review>\n"
            "  </book>\n"
            "</burn:books>\n")
        self.assertEqual(expected, actual)
示例#2
0
 def test_property_prefixes(self):
     namespaces = Namespaces()
     namespaces.add_all({
         "b": "bar",
         None: "http://www.w3.org/2001/XMLSchema",
         "foo": "http://www.w3.org/2001/XMLSchema-instance",
     })
     self.assertEqual(["b", "xs", "xsi"], namespaces.prefixes)
示例#3
0
 def test_add_all(self):
     namespaces = Namespaces()
     namespaces.add_all({
         "b": "bar",
         None: "http://www.w3.org/2001/XMLSchema",
         "foo": "http://www.w3.org/2001/XMLSchema-instance",
     })
     expected = {
         "bar": {"b"},
         "http://www.w3.org/2001/XMLSchema": {"xs"},
         "http://www.w3.org/2001/XMLSchema-instance": {"xsi"},
     }
     self.assertEqual(expected, namespaces.items)
示例#4
0
    def test_add(self):
        namespaces = Namespaces()
        namespaces.add("foo")
        namespaces.add("foo")
        namespaces.add("bar", "one")
        namespaces.add("bar", "two")
        namespaces.add(Namespace.XSI.uri, "a")
        namespaces.add(Namespace.XSI.uri, "b")
        namespaces.add(Namespace.XS.uri, "c")
        namespaces.add(Namespace.XS.uri, "d")

        expected = {
            "bar": {"one", "two"},
            "foo": {"ns0"},
            "http://www.w3.org/2001/XMLSchema": {"xs"},
            "http://www.w3.org/2001/XMLSchema-instance": {"xsi"},
        }
        self.assertEqual(expected, namespaces.items)
示例#5
0
    def test_register(self):
        namespaces = Namespaces()
        namespaces.add("http://komposta.net", "bar")
        namespaces.add("http://foobar", "ns2")  # ns{\d} are not registered

        element = Element("{http://komposta.net}root")
        self.assertEqual({"ns0": "http://komposta.net"}, element.nsmap)

        namespaces.register()
        element = Element("{http://komposta.net}root")
        self.assertEqual({"bar": "http://komposta.net"}, element.nsmap)

        element = Element("{http://foobar}root")
        self.assertEqual({"ns0": "http://foobar"}, element.nsmap)
示例#6
0
 def test_clear(self):
     namespaces = Namespaces()
     namespaces.add_all({
         "b": "bar",
         "foo": "http://www.w3.org/2001/XMLSchema-instance"
     })
     self.assertEqual(2, len(namespaces.ns_map))
     namespaces.clear()
     self.assertEqual(0, len(namespaces.ns_map))
示例#7
0
    def render_sub_nodes(
        self, parent, values: Any, var: ClassVar, namespaces: Namespaces
    ):
        if not isinstance(values, list):
            values = [values]

        is_wildcard = var.is_any_element

        for value in values:
            if value is None:
                continue
            elif not is_wildcard:
                sub_element = SubElement(parent, var.qname)
                self.render_node(value, sub_element, namespaces)
                self.set_nil_attribute(sub_element, var.nillable, namespaces)
            elif isinstance(value, str):
                if parent.text:
                    self.set_tail(parent, value)
                else:
                    self.set_text(parent, value)
            elif isinstance(value, AnyElement):
                if value.qname:
                    sub_element = SubElement(parent, value.qname)
                else:
                    sub_element = parent

                namespaces.add_all(value.ns_map)
                self.set_text(sub_element, value.text)
                self.set_tail(sub_element, value.tail)
                self.set_attributes(sub_element, value.attributes)
                for child in value.children:
                    self.render_sub_nodes(sub_element, child, var, namespaces)
                    self.set_nil_attribute(parent, var.nillable, namespaces)
            else:
                sub_element = SubElement(parent, value.qname)
                self.render_node(value, sub_element, namespaces)
                self.set_nil_attribute(sub_element, var.nillable, namespaces)
示例#8
0
    def render_node(self, obj, parent, namespaces: Namespaces) -> Element:
        """Recursively traverse the given dataclass instance fields and build
        the lxml Element structure."""
        if not is_dataclass(obj):
            self.set_text(parent, obj)
            return parent

        meta = self.class_meta(obj.__class__, QName(parent).namespace)
        for var, value in self.next_value(meta, obj):
            if value is not None:
                if not var.is_any_element and not var.is_any_attribute:
                    namespaces.add(var.namespace)

                if var.is_attribute:
                    self.set_attribute(parent, var.qname, value)
                elif var.is_any_attribute:
                    self.set_attributes(parent, value)
                elif var.is_text:
                    self.set_text(parent, value)
                else:
                    self.render_sub_nodes(parent, value, var, namespaces)

        self.set_nil_attribute(parent, meta.nillable, namespaces)
        return parent
示例#9
0
    def render_tree(self, obj: Any, namespaces: Optional[Namespaces] = None) -> Element:
        """
        Convert a dataclass instance to a nested Element structure.

        Optionally provide a namespaces instance with a predefined list
        of namespace uris and prefixes.
        """
        meta = self.class_meta(obj.__class__)
        namespaces = namespaces or Namespaces()
        namespaces.register()
        namespaces.add(meta.namespace)

        root = self.render_node(obj, Element(meta.qname), namespaces)
        cleanup_namespaces(
            root, top_nsmap=namespaces.ns_map, keep_ns_prefixes=namespaces.prefixes
        )
        return root
示例#10
0
    def test_property_ns_map(self):
        namespaces = Namespaces()
        namespaces.add_all({
            "b": "bar",
            None: "http://www.w3.org/2001/XMLSchema",
            "foo": "http://www.w3.org/2001/XMLSchema-instance",
        })
        namespaces.add("bar", "again")
        namespaces.add("one")
        namespaces.add("two")

        expected = {
            "b": "bar",
            "again": "bar",
            "ns0": "one",
            "ns1": "two",
            "xs": "http://www.w3.org/2001/XMLSchema",
            "xsi": "http://www.w3.org/2001/XMLSchema-instance",
        }
        self.assertEqual(expected, namespaces.ns_map)
示例#11
0
 def set_nil_attribute(
     cls, element: Element, nillable: bool, namespaces: Namespaces
 ):
     if nillable and element.text is None and len(element) == 0:
         namespaces.add(Namespace.XSI.uri, Namespace.XSI.prefix)
         element.set(QNames.XSI_NIL, "true")