1818
1919package com .tickaroo .tikxml ;
2020
21- import java .io .Closeable ;
22- import java .io .IOException ;
2321import okio .BufferedSink ;
2422import okio .ByteString ;
2523
26- import static com .tickaroo .tikxml .XmlScope .ELEMENT_CONTENT ;
27- import static com .tickaroo .tikxml .XmlScope .ELEMENT_OPENING ;
28- import static com .tickaroo .tikxml .XmlScope .NONEMPTY_DOCUMENT ;
29- import static com .tickaroo .tikxml .XmlScope .getTopStackElementAsToken ;
24+ import java .io .Closeable ;
25+ import java .io .IOException ;
26+ import java .nio .charset .Charset ;
27+ import java .nio .charset .StandardCharsets ;
28+
29+ import static com .tickaroo .tikxml .XmlScope .*;
3030
3131/**
3232 * With this class you can write xml with a convinient API.
@@ -75,16 +75,16 @@ public class XmlWriter implements Closeable {
7575 private static final Byte DOUBLE_QUOTE = (byte ) '"' ;
7676 private static final Byte OPENING_XML_ELEMENT = (byte ) '<' ;
7777 private static final Byte CLOSING_XML_ELEMENT = (byte ) '>' ;
78- private static final ByteString CLOSING_XML_ELEMENT_START = ByteString .encodeUtf8 ("</" );
79- private static final ByteString INLINE_CLOSING_XML_ELEMENT = ByteString .encodeUtf8 ("/>" );
80- private static final ByteString ATTRIBUTE_ASSIGNMENT_BEGIN = ByteString .encodeUtf8 ("=\" " );
81- private static final ByteString OPENING_CDATA = ByteString .encodeUtf8 ("<![CDATA[" );
82- private static final ByteString CLOSING_CDATA = ByteString .encodeUtf8 ("]]>" );
83- private static final ByteString XML_DECLARATION =
84- ByteString .encodeUtf8 ("<?xml version=\" 1.0\" encoding=\" UTF-8\" ?>" );
78+ private final ByteString CLOSING_XML_ELEMENT_START ;
79+ private final ByteString INLINE_CLOSING_XML_ELEMENT ;
80+ private final ByteString ATTRIBUTE_ASSIGNMENT_BEGIN ;
81+ private final ByteString OPENING_CDATA ;
82+ private final ByteString CLOSING_CDATA ;
83+ private final ByteString XML_DECLARATION ;
8584
8685 /** The output data, containing at most one top-level array or object. */
8786 private final BufferedSink sink ;
87+ private final Charset charset ;
8888 private boolean xmlDeclarationWritten = false ;
8989
9090 private int [] stack = new int [32 ];
@@ -97,18 +97,30 @@ public class XmlWriter implements Closeable {
9797 stack [stackSize ++] = XmlScope .EMPTY_DOCUMENT ;
9898 }
9999
100- private XmlWriter (BufferedSink sink ) {
100+ private XmlWriter (BufferedSink sink , Charset charset ) {
101101 if (sink == null ) {
102102 throw new NullPointerException ("sink == null" );
103103 }
104104 this .sink = sink ;
105+ this .charset = charset ;
106+
107+ CLOSING_XML_ELEMENT_START = ByteString .encodeString ("</" , charset );
108+ INLINE_CLOSING_XML_ELEMENT = ByteString .encodeString ("/>" , charset );
109+ ATTRIBUTE_ASSIGNMENT_BEGIN = ByteString .encodeString ("=\" " , charset );
110+ OPENING_CDATA = ByteString .encodeString ("<![CDATA[" , charset );
111+ CLOSING_CDATA = ByteString .encodeString ("]]>" , charset );
112+ XML_DECLARATION = ByteString .encodeString ("<?xml version=\" 1.0\" encoding=\" " + charset .name () + "\" ?>" , charset );
105113 }
106114
107115 /**
108116 * Returns a new instance.
109117 */
110118 public static XmlWriter of (BufferedSink source ) {
111- return new XmlWriter (source );
119+ return new XmlWriter (source , StandardCharsets .UTF_8 );
120+ }
121+
122+ public static XmlWriter of (BufferedSink source , Charset charset ) {
123+ return new XmlWriter (source , charset );
112124 }
113125
114126 private void pushStack (int newTop ) {
@@ -190,14 +202,14 @@ public XmlWriter beginElement(String elementTagName) throws IOException {
190202 pushStack (XmlScope .ELEMENT_OPENING );
191203 pathNames [stackSize - 1 ] = elementTagName ;
192204 sink .writeByte (OPENING_XML_ELEMENT )
193- .writeUtf8 (elementTagName );
205+ .writeString (elementTagName , charset );
194206 break ;
195207
196208 case XmlScope .ELEMENT_CONTENT : // write a nested xml element <parent> Some optional text <nested>
197209 pushStack (XmlScope .ELEMENT_OPENING );
198210 pathNames [stackSize - 1 ] = elementTagName ;
199211 sink .writeByte (OPENING_XML_ELEMENT )
200- .writeUtf8 (elementTagName );
212+ .writeString (elementTagName , charset );
201213 break ;
202214
203215 case XmlScope .ELEMENT_OPENING : // write a nested xml element by closing the parent's xml opening header
@@ -206,7 +218,7 @@ public XmlWriter beginElement(String elementTagName) throws IOException {
206218 pathNames [stackSize - 1 ] = elementTagName ;
207219 sink .writeByte (CLOSING_XML_ELEMENT )
208220 .writeByte (OPENING_XML_ELEMENT )
209- .writeUtf8 (elementTagName );
221+ .writeString (elementTagName , charset );
210222 break ;
211223
212224 case XmlScope .NONEMPTY_DOCUMENT :
@@ -239,7 +251,7 @@ public XmlWriter endElement() throws IOException {
239251 break ;
240252 case XmlScope .ELEMENT_CONTENT :
241253 sink .write (CLOSING_XML_ELEMENT_START )
242- .writeUtf8 (pathNames [stackSize - 1 ])
254+ .writeString (pathNames [stackSize - 1 ], charset )
243255 .writeByte (CLOSING_XML_ELEMENT );
244256 popStack ();
245257 break ;
@@ -273,11 +285,11 @@ public XmlWriter textContent(String textContentValue) throws IOException {
273285 case ELEMENT_OPENING :
274286 sink .writeByte (CLOSING_XML_ELEMENT );
275287 replaceTopOfStack (XmlScope .ELEMENT_CONTENT );
276- sink .writeUtf8 (textContentValue );
288+ sink .writeString (textContentValue , charset );
277289 break ;
278290
279291 case ELEMENT_CONTENT :
280- sink .writeUtf8 (textContentValue );
292+ sink .writeString (textContentValue , charset );
281293 break ;
282294
283295 default :
@@ -346,13 +358,13 @@ public XmlWriter textContentAsCData(String textContentValue) throws IOException
346358 replaceTopOfStack (XmlScope .ELEMENT_CONTENT );
347359 sink .writeByte (CLOSING_XML_ELEMENT )
348360 .write (OPENING_CDATA )
349- .writeUtf8 (textContentValue )
361+ .writeString (textContentValue , charset )
350362 .write (CLOSING_CDATA );
351363 break ;
352364
353365 case ELEMENT_CONTENT :
354366 sink .write (OPENING_CDATA )
355- .writeUtf8 (textContentValue )
367+ .writeString (textContentValue , charset )
356368 .write (CLOSING_CDATA );
357369 break ;
358370
@@ -386,9 +398,9 @@ public XmlWriter textContentAsCData(String textContentValue) throws IOException
386398 public XmlWriter attribute (String attributeName , String value ) throws IOException {
387399 if (XmlScope .ELEMENT_OPENING == peekStack ()) {
388400 sink .writeByte (' ' ) // Write a whitespace
389- .writeUtf8 (attributeName )
401+ .writeString (attributeName , charset )
390402 .write (ATTRIBUTE_ASSIGNMENT_BEGIN )
391- .writeUtf8 (value )
403+ .writeString (value , charset )
392404 .writeByte (DOUBLE_QUOTE );
393405 } else {
394406 throw syntaxError ("Error while trying to write attribute "
@@ -462,14 +474,14 @@ public XmlWriter xmlDeclaration() throws IOException {
462474 sink .write (XML_DECLARATION );
463475 xmlDeclarationWritten = true ;
464476 } else {
465- throw syntaxError ("Xml Declatraion "
466- + XML_DECLARATION .utf8 ( )
477+ throw syntaxError ("Xml Declaration "
478+ + XML_DECLARATION .string ( charset )
467479 + " can only be written at the beginning of a xml document! You are not at the beginning of a xml document: current xml scope is "
468480 + XmlScope .getTopStackElementAsToken (stackSize , stack ));
469481 }
470482 } else {
471483 throw new IOException ("Xml declaration "
472- + XML_DECLARATION .utf8 ( )
484+ + XML_DECLARATION .string ( charset )
473485 + " has already been written in this xml document. Xml declaration can only be written once at the beginning of the document." );
474486 }
475487
0 commit comments