Sam Whited | 0a464ba | 2018-09-01 14:50:20 -0500 | [diff] [blame] | 1 | # Proposal: Raw XML Token |
| 2 | |
| 3 | Author(s): Sam Whited <sam@samwhited.com> |
| 4 | |
| 5 | Last updated: 2018-09-01 |
| 6 | |
| 7 | Discussion at https://golang.org/issue/26756 |
| 8 | |
| 9 | CL at https://golang.org/cl/127435 |
| 10 | |
| 11 | |
| 12 | ## Abstract |
| 13 | |
| 14 | This proposal defines a mechanism by which users can emulate the `,innerxml` |
| 15 | struct tag using XML tokens. |
| 16 | |
| 17 | |
| 18 | ## Background |
| 19 | |
| 20 | When using the `"*Encoder".EncodeToken` API to write tokens to an XML stream, |
| 21 | it is currently not possible to fully emulate the behavior of `Marshal`. |
| 22 | Specifically, there is no functionality that lets users output XML equivalent to |
| 23 | the `,innerxml` struct tag which inserts raw, unescaped, XML into the output. |
| 24 | For example, consider the following: |
| 25 | |
| 26 | e := xml.NewEncoder(os.Stdout) |
| 27 | e.Encode(struct { |
| 28 | XMLName xml.Name `xml:"raw"` |
| 29 | Inner string `xml:",innerxml"` |
| 30 | }{ |
| 31 | Inner: `<test:test xmlns:test="urn:example:golang"/>`, |
| 32 | }) |
| 33 | // Output: <raw><test:test xmlns:test="urn:example:golang"/></raw> |
| 34 | |
| 35 | This cannot be done with the token based output because all token types are |
| 36 | currently escaped. |
| 37 | For example, attempting to output the raw XML as character data results in the |
| 38 | following: |
| 39 | |
| 40 | e.EncodeToken(xml.CharData(rawOut)) |
| 41 | e.Flush() |
| 42 | // <test:test xmlns:test="urn:example:golang"> |
| 43 | |
| 44 | |
| 45 | ## Proposal |
| 46 | |
| 47 | The proposed API introduces an XML pseudo-token: `RawXML`. |
| 48 | |
| 49 | ```go |
| 50 | // RawXML represents some data that should be passed through without escaping. |
| 51 | // Like a struct field with the ",innerxml" tag, RawXML is written to the |
| 52 | // stream verbatim and is not subject to the usual escaping rules. |
| 53 | type RawXML []byte |
| 54 | |
| 55 | // Copy creates a new copy of RawXML. |
| 56 | func (r RawXML) Copy() RawXML { … } |
| 57 | ``` |
| 58 | |
| 59 | |
| 60 | ## Rationale |
| 61 | |
| 62 | When attempting to match the output of legacy XML encoders which may produce |
| 63 | broken escaping, or match the output of XML encoders that support features that |
| 64 | are not currently supported by the [`encoding/xml`] package such as namespace |
| 65 | prefixes it is often desirable to use `,rawxml`. |
| 66 | However, if the user is primarily using the token stream API, it may not be |
| 67 | desirable to switch between encoding tokens and encoding native structures which |
| 68 | is cumbersome and forces a call to `Flush`. |
| 69 | |
| 70 | Being able to generate the same output from both the SAX-like and DOM-like APIs |
| 71 | would also allow future proposals the option of fully unifying the two APIs by |
| 72 | creating an encoder equivalent to the `NewTokenDecoder` function. |
| 73 | |
| 74 | |
| 75 | ## Compatibility |
| 76 | |
| 77 | This proposal introduces one new exported type that would be covered by the |
| 78 | compatibility promise. |
| 79 | |
| 80 | |
| 81 | ## Implementation |
| 82 | |
| 83 | Implementation of this proposal is trivial, comprising some 5 lines of code |
| 84 | (excluding tests and comments). |
| 85 | [CL 127435] has been created to demonstrate the concept. |
| 86 | |
| 87 | |
| 88 | ## Open issues |
| 89 | |
| 90 | None. |
| 91 | |
| 92 | |
| 93 | [`encoding/xml`]: https://golang.org/pkg/encoding/xml/ |
| 94 | [CL 127435]: https://golang.org/cl/127435 |