diff --git a/pkgs/racket-doc/xml/xml.scrbl b/pkgs/racket-doc/xml/xml.scrbl index a2f1da02a0..b8e193dc94 100644 --- a/pkgs/racket-doc/xml/xml.scrbl +++ b/pkgs/racket-doc/xml/xml.scrbl @@ -300,6 +300,23 @@ Converts an @tech{X-expression} into a string containing XML.} Converts XML represented with a string into an @tech{X-expression}.} +@defproc[(xml-encode-attribute [str string?]) string?]{ + +Escapes a string as required for XML attributes. + +The escaping performed for attribute strings is slightly +different from that performed for body strings, in that +double-quotes must be escaped, as they would otherwise +terminate the enclosing string. + +Note that this conversion is performed automatically in attribute +positions by @racket[xexpr->string], and you are therefore unlikely to +need this function unless you are using @racket[include-template] to +insert strings directly into attribute positions of HTML. + +@history[#:added "6.6.0.7"] +} + @defproc[((eliminate-whitespace [tags (listof symbol?) empty] [choose (boolean? . -> . boolean?) (λ (x) x)]) [elem element?]) diff --git a/pkgs/racket-test/tests/xml/test.rkt b/pkgs/racket-test/tests/xml/test.rkt index fb5c2e5783..f3919d8840 100644 --- a/pkgs/racket-test/tests/xml/test.rkt +++ b/pkgs/racket-test/tests/xml/test.rkt @@ -540,6 +540,10 @@ END (test-suite "xml->xexpr" + + (test-equal? "xml-attribute-encode" + (xml-attribute-encode "ab\"cd?e;; %"f") + "ab"cd?e;;<i> %&quot;f") (test-xml->xexpr "hi there!" '(doc () (bold () "hi") " there!")) diff --git a/racket/collects/xml/private/writer.rkt b/racket/collects/xml/private/writer.rkt index ae87812be0..5ee0912cab 100644 --- a/racket/collects/xml/private/writer.rkt +++ b/racket/collects/xml/private/writer.rkt @@ -166,7 +166,7 @@ [(#\") """] [else c])) -;; escape : String -> String +;; escape : String Regexp -> String (define (escape x table) (regexp-replace* table x replace-escaped)) diff --git a/racket/collects/xml/private/xexpr.rkt b/racket/collects/xml/private/xexpr.rkt index 940deeee64..32098c1460 100644 --- a/racket/collects/xml/private/xexpr.rkt +++ b/racket/collects/xml/private/xexpr.rkt @@ -101,6 +101,7 @@ [xml->xexpr (content/c . -> . xexpr/c)] [xexpr->xml (xexpr/c . -> . content/c)] [xexpr-drop-empty-attributes (parameter/c boolean?)] + [xml-attribute-encode (string? . -> . string?)] [write-xexpr (->* (xexpr/c) (output-port? #:insert-newlines? any/c) @@ -168,3 +169,9 @@ [(p-i? x) (write-xml-p-i x 0 void out)])) (void)) + +;; given a string, encode it in the style required for attributes. Specifically, +;; double-quote must be encoded as well as <, >, and &, because the double-quote +;; would otherwise end the attribute. +(define (xml-attribute-encode str) + (escape str escape-attribute-table))