compatibility.txt 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. =======================================
  2. ElementTree compatibility of lxml.etree
  3. =======================================
  4. A lot of care has been taken to ensure compatibility between etree and
  5. ElementTree. Nonetheless, some differences and incompatibilities exist:
  6. * Importing etree is obviously different; etree uses a lower-case
  7. package name, while ElementTree uses a combination of upper-case and
  8. lower case in imports:
  9. .. sourcecode:: python
  10. # etree
  11. from lxml.etree import Element
  12. # ElementTree
  13. from elementtree.ElementTree import Element
  14. # ElementTree in the Python 2.5 standard library
  15. from xml.etree.ElementTree import Element
  16. When switching over code from ElementTree to lxml.etree, and you're using
  17. the package name prefix 'ElementTree', you can do the following:
  18. .. sourcecode:: python
  19. # instead of
  20. from elementtree import ElementTree
  21. # use
  22. from lxml import etree as ElementTree
  23. * lxml.etree offers a lot more functionality, such as XPath, XSLT, Relax NG,
  24. and XML Schema support, which (c)ElementTree does not offer.
  25. * etree has a different idea about Python unicode strings than ElementTree.
  26. In most parts of the API, ElementTree uses plain strings and unicode strings
  27. as what they are. This includes Element.text, Element.tail and many other
  28. places. However, the ElementTree parsers assume by default that any string
  29. (`str` or `unicode`) contains ASCII data. They raise an exception if
  30. strings do not match the expected encoding.
  31. etree has the same idea about plain strings (`str`) as ElementTree. For
  32. unicode strings, however, etree assumes throughout the API that they are
  33. Python unicode encoded strings rather than byte data. This includes the
  34. parsers. It is therefore perfectly correct to pass XML unicode data into
  35. the etree parsers in form of Python unicode strings. It is an error, on the
  36. other hand, if unicode strings specify an encoding in their XML declaration,
  37. as this conflicts with the characteristic encoding of Python unicode
  38. strings.
  39. * ElementTree allows you to place an Element in two different trees at the
  40. same time. Thus, this:
  41. .. sourcecode:: python
  42. a = Element('a')
  43. b = SubElement(a, 'b')
  44. c = Element('c')
  45. c.append(b)
  46. will result in the following tree a:
  47. .. sourcecode:: xml
  48. <a><b /></a>
  49. and the following tree c:
  50. .. sourcecode:: xml
  51. <c><b /></c>
  52. In lxml, this behavior is different, because lxml is built on top of a tree
  53. that maintains parent relationships for elements (like W3C DOM). This means
  54. an element can only exist in a single tree at the same time. Adding an
  55. element in some tree to another tree will cause this element to be moved.
  56. So, for tree a we will get:
  57. .. sourcecode:: xml
  58. <a></a>
  59. and for tree c we will get:
  60. .. sourcecode:: xml
  61. <c><b/></c>
  62. Unfortunately this is a rather fundamental difference in behavior, which is
  63. hard to change. It won't affect some applications, but if you want to port
  64. code you must unfortunately make sure that it doesn't affect yours.
  65. * etree allows navigation to the parent of a node by the ``getparent()``
  66. method and to the siblings by calling ``getnext()`` and ``getprevious()``.
  67. This is not possible in ElementTree as the underlying tree model does not
  68. have this information.
  69. * When trying to set a subelement using __setitem__ that is in fact not an
  70. Element but some other object, etree raises a TypeError, and ElementTree
  71. raises an AssertionError. This also applies to some other places of the
  72. API. In general, etree tries to avoid AssertionErrors in favour of being
  73. more specific about the reason for the exception.
  74. * When parsing fails in ``iterparse()``, ElementTree up to version
  75. 1.2.x raises a low-level ``ExpatError`` instead of a ``SyntaxError``
  76. as the other parsers. Both lxml and ElementTree 1.3 raise a
  77. ``ParseError`` for parser errors.
  78. * The ``iterparse()`` function in lxml is implemented based on the libxml2
  79. parser and tree generator. This means that modifications of the document
  80. root or the ancestors of the current element during parsing can irritate the
  81. parser and even segfault. While this is not a problem in the Python object
  82. structure used by ElementTree, the C tree underlying lxml suffers from it.
  83. The golden rule for ``iterparse()`` on lxml therefore is: do not touch
  84. anything that will have to be touched again by the parser later on. See the
  85. lxml parser documentation on this.
  86. * ElementTree ignores comments and processing instructions when parsing XML,
  87. while etree will read them in and treat them as Comment or
  88. ProcessingInstruction elements respectively. This is especially visible
  89. where comments are found inside text content, which is then split by the
  90. Comment element.
  91. You can disable this behaviour by passing the boolean ``remove_comments``
  92. and/or ``remove_pis`` keyword arguments to the parser you use. For
  93. convenience and to support portable code, you can also use the
  94. ``etree.ETCompatXMLParser`` instead of the default ``etree.XMLParser``. It
  95. tries to provide a default setup that is as close to the ElementTree parser
  96. as possible.
  97. * The ``TreeBuilder`` class of ``lxml.etree`` uses a different
  98. signature for the ``start()`` method. It accepts an additional
  99. argument ``nsmap`` to propagate the namespace declarations of an
  100. element in addition to its own namespace. To assure compatibility
  101. with ElementTree (which does not support this argument), lxml checks
  102. if the method accepts 3 arguments before calling it, and otherwise
  103. drops the namespace mapping. This should work with most existing
  104. ElementTree code, although there may still be conflicting cases.
  105. * ElementTree 1.2 has a bug when serializing an empty Comment (no text
  106. argument given) to XML, etree serializes this successfully.
  107. * ElementTree adds whitespace around comments on serialization, lxml does
  108. not. This means that a comment text "text" that ElementTree serializes as
  109. "<!-- text -->" will become "<!--text-->" in lxml.
  110. * When the string '*' is used as tag filter in the ``Element.getiterator()``
  111. method, ElementTree returns all elements in the tree, including comments and
  112. processing instructions. lxml.etree only returns real Elements, i.e. tree
  113. nodes that have a string tag name. Without a filter, both libraries iterate
  114. over all nodes.
  115. Note that currently only lxml.etree supports passing the ``Element`` factory
  116. function as filter to select only Elements. Both libraries support passing
  117. the ``Comment`` and ``ProcessingInstruction`` factories to select the
  118. respective tree nodes.
  119. * ElementTree merges the target of a processing instruction into ``PI.text``,
  120. while lxml.etree puts it into the ``.target`` property and leaves it out of
  121. the ``.text`` property. The ``pi.text`` in ElementTree therefore
  122. correspondents to ``pi.target + " " + pi.text`` in lxml.etree.
  123. * Because etree is built on top of libxml2, which is namespace prefix aware,
  124. etree preserves namespaces declarations and prefixes while ElementTree tends
  125. to come up with its own prefixes (ns0, ns1, etc). When no namespace prefix
  126. is given, however, etree creates ElementTree style prefixes as well.
  127. * etree has a 'prefix' attribute (read-only) on elements giving the Element's
  128. prefix, if this is known, and None otherwise (in case of no namespace at
  129. all, or default namespace).
  130. * etree further allows passing an 'nsmap' dictionary to the Element and
  131. SubElement element factories to explicitly map namespace prefixes to
  132. namespace URIs. These will be translated into namespace declarations on
  133. that element. This means that in the probably rare case that you need to
  134. construct an attribute called 'nsmap', you need to be aware that unlike in
  135. ElementTree, you cannot pass it as a keyword argument to the Element and
  136. SubElement factories directly.
  137. * ElementTree allows QName objects as attribute values and resolves their
  138. prefix on serialisation (e.g. an attribute value ``QName("{myns}myname")``
  139. becomes "p:myname" if "p" is the namespace prefix of "myns"). lxml.etree
  140. also allows you to set attribute values from QName instances (and also .text
  141. values), but it resolves their prefix immediately and stores the plain text
  142. value. So, if prefixes are modified later on, e.g. by moving a subtree to a
  143. different tree (which reassigns the prefix mappings), the text values will
  144. not be updated and you might end up with an undefined prefix.
  145. * etree elements can be copied using ``copy.deepcopy()`` and ``copy.copy()``,
  146. just like ElementTree's. However, ``copy.copy()`` does *not* create a
  147. shallow copy where elements are shared between trees, as this makes no sense
  148. in the context of libxml2 trees. Note that lxml can deep-copy trees
  149. considerably faster than ElementTree, so a deep copy might still be fast
  150. enough to replace a shallow copy in your case.