diff --git a/Doc/lib/xmlsaxutils.tex b/Doc/lib/xmlsaxutils.tex index 2ff14716a86..004848523cb 100644 --- a/Doc/lib/xmlsaxutils.tex +++ b/Doc/lib/xmlsaxutils.tex @@ -14,13 +14,33 @@ functions that are commonly useful when creating SAX applications, either in direct use, or as base classes. \begin{funcdesc}{escape}{data\optional{, entities}} - Escape \&, <, and > in a string of data. + Escape \character{\&}, \character{<}, and \character{>} in a string + of data. You can escape other strings of data by passing a dictionary as the - optional entities parameter. The keys and values must all be + optional \var{entities} parameter. The keys and values must all be strings; each key will be replaced with its corresponding value. \end{funcdesc} +\begin{funcdesc}{quoteattr}{data\optional{, entities}} + Similar to \function{escape()}, but also prepares \var{data} to be + used as an attribute value. The return value is a quoted version of + \var{data} with any additional required replacements. + \function{quoteattr()} will select a quote character based on the + content of \var{data}, attempting to avoid encoding any quote + characters in the string. If both single- and double-quote + characters are already in \var{data}, the double-quote characters + will be encoded and \var{data} will be wrapped in doule-quotes. The + resulting string can be used directly as an attribute value: + +\begin{verbatim} +>>> print "" % quoteattr("ab ' cd \" ef") + +\end{verbatim} + + \versionadded{2.2} +\end{funcdesc} + \begin{classdesc}{XMLGenerator}{\optional{out\optional{, encoding}}} This class implements the \class{ContentHandler} interface by writing SAX events back into an XML document. In other words, using diff --git a/Lib/test/output/test_sax b/Lib/test/output/test_sax index de49c805618..b14cf94812d 100644 --- a/Lib/test/output/test_sax +++ b/Lib/test/output/test_sax @@ -1,6 +1,7 @@ test_sax Passed test_attrs_empty Passed test_attrs_wattr +Passed test_double_quoteattr Passed test_escape_all Passed test_escape_basic Passed test_escape_extra @@ -25,10 +26,13 @@ Passed test_make_parser Passed test_make_parser2 Passed test_nsattrs_empty Passed test_nsattrs_wattr +Passed test_quoteattr_basic +Passed test_single_double_quoteattr +Passed test_single_quoteattr Passed test_xmlgen_basic Passed test_xmlgen_content Passed test_xmlgen_content_escape Passed test_xmlgen_ignorable Passed test_xmlgen_ns Passed test_xmlgen_pi -32 tests, 0 failures +36 tests, 0 failures diff --git a/Lib/test/test_sax.py b/Lib/test/test_sax.py index f4b43fede83..62705c9bcaf 100644 --- a/Lib/test/test_sax.py +++ b/Lib/test/test_sax.py @@ -8,7 +8,7 @@ except SAXReaderNotAvailable: # don't try to test this module if we cannot create a parser raise ImportError("no XML parsers available") -from xml.sax.saxutils import XMLGenerator, escape, XMLFilterBase +from xml.sax.saxutils import XMLGenerator, escape, quoteattr, XMLFilterBase from xml.sax.expatreader import create_parser from xml.sax.xmlreader import InputSource, AttributesImpl, AttributesNSImpl from cStringIO import StringIO @@ -69,6 +69,25 @@ def test_escape_all(): def test_escape_extra(): return escape("Hei på deg", {"å" : "å"}) == "Hei på deg" +# ===== quoteattr + +def test_quoteattr_basic(): + return quoteattr("Donald Duck & Co") == '"Donald Duck & Co"' + +def test_single_quoteattr(): + return (quoteattr('Includes "double" quotes') + == '\'Includes "double" quotes\'') + +def test_double_quoteattr(): + return (quoteattr("Includes 'single' quotes") + == "\"Includes 'single' quotes\"") + +def test_single_double_quoteattr(): + return (quoteattr("Includes 'single' and \"double\" quotes") + == "\"Includes 'single' and "double" quotes\"") + +# ===== make_parser + def test_make_parser(): try: # Creating a parser should succeed - it should fall back diff --git a/Lib/xml/sax/saxutils.py b/Lib/xml/sax/saxutils.py index e592f2a1d90..bf1f5f317e9 100644 --- a/Lib/xml/sax/saxutils.py +++ b/Lib/xml/sax/saxutils.py @@ -27,6 +27,27 @@ def escape(data, entities={}): data = data.replace(chars, entity) return data +def quoteattr(data, entities={}): + """Escape and quote an attribute value. + + Escape &, <, and > in a string of data, then quote it for use as + an attribute value. The \" character will be escaped as well, if + necessary. + + You can escape other strings of data by passing a dictionary as + the optional entities parameter. The keys and values must all be + strings; each key will be replaced with its corresponding value. + """ + data = escape(data, entities) + if '"' in data: + if "'" in data: + data = '"%s"' % data.replace('"', """) + else: + data = "'%s'" % data + else: + data = '"%s"' % data + return data + class XMLGenerator(handler.ContentHandler):