# (c) 2009-2024 Martin Wendt and contributors; see WsgiDAV https://github.com/mar10/wsgidav# Original PyFileServer (c) 2005 Ho Chun Wei.# Licensed under the MIT license:# http://www.opensource.org/licenses/mit-license.php"""Small wrapper for different etree packages."""importloggingfromioimportStringIO__docformat__="reStructuredText"# _logger = util.get_module_logger(__name__)_logger=logging.getLogger("wsgidav")# Import XML supportuse_lxml=Falsetry:fromlxmlimportetreeuse_lxml=True_ElementType=etree._ElementexceptImportError:# defusedxml doesn't define these non-parsing related objectsfromxml.etree.ElementTreeimportElement,SubElement,tostringfromdefusedxmlimportElementTreeasetreeetree.Element=_ElementType=Elementetree.SubElement=SubElementetree.tostring=tostring# ========================================================================# XML# ========================================================================
[docs]defstring_to_xml(text):"""Convert XML string into etree.Element."""try:returnetree.XML(text)exceptException:# TODO:# ExpatError: reference to invalid character number: line 1, column 62# litmus fails, when xml is used instead of lxml# 18. propget............... FAIL (PROPFIND on `/temp/litmus/prop2':# Could not read status line: connection was closed by server)# text = <ns0:high-unicode xmlns:ns0="http://example.com/neon/litmus/">��# </ns0:high-unicode># t2 = text.encode("utf8")# return etree.XML(t2)_logger.error("Error parsing XML string. ""If lxml is not available, and unicode is involved, then ""installing lxml _may_ solve this issue.")_logger.error(f"XML source: {text}")raise
[docs]defxml_to_bytes(element,*,pretty=False):"""Wrapper for etree.tostring, that takes care of unsupported pretty_print option and prepends an encoding header."""ifuse_lxml:xml=etree.tostring(# pylint: disable=unexpected-keyword-argelement,encoding="UTF-8",xml_declaration=True,pretty_print=pretty,)else:xml=etree.tostring(element,encoding="UTF-8")ifnotxml.startswith(b"<?xml "):xml=b'<?xml version="1.0" encoding="utf-8" ?>\n'+xmlassertxml.startswith(b"<?xml ")# ET should prepend an encoding headerreturnxml
[docs]defmake_multistatus_el():"""Wrapper for etree.Element, that takes care of unsupported nsmap option."""ifuse_lxml:returnetree.Element("{DAV:}multistatus",nsmap={"D":"DAV:"})returnetree.Element("{DAV:}multistatus")
[docs]defmake_prop_elem():"""Wrapper for etree.Element, that takes care of unsupported nsmap option."""ifuse_lxml:returnetree.Element("{DAV:}prop",nsmap={"D":"DAV:"})returnetree.Element("{DAV:}prop")
[docs]defmake_sub_element(parent,tag,*,nsmap=None):"""Wrapper for etree.SubElement, that takes care of unsupported nsmap option."""ifuse_lxml:returnetree.SubElement(parent,tag,nsmap=nsmap)returnetree.SubElement(parent,tag)
[docs]defelement_content_as_string(element):"""Serialize etree.Element. Note: element may contain more than one child or only text (i.e. no child at all). Therefore the resulting string may raise an exception, when passed back to etree.XML(). """iflen(element)==0:returnelement.textor""# Make sure, None is returned as ''stream=StringIO()forchildnodeinelement:stream.write(xml_to_bytes(childnode,pretty=False)+"\n")# print(xml_to_bytes(childnode, pretty=False), file=stream)s=stream.getvalue()stream.close()returns