dxml.writer
This module provides functionality for creating XML 1.0 documents.
Primary Symbols
Symbol | Description |
---|---|
XMLWriter | Type used for writing XML documents. |
xmlWriter | Function used to create an XMLWriter. |
Helper Types
XMLWritingException | Thrown by XMLWriter when it's given data that would result in invalid XML. |
Helper Functions
Symbol | Description |
---|---|
writeTaggedText | Shortcut for writing text enclosed by tags. e.g. <tag>text</tag>. |
writeXMLDecl | Writes the optional XML declaration that goes at the top of an XML document to an ouput range. |
License:
Boost License 1.0.
See Also:
Official Specification for XML 1.0
- class
XMLWritingException
: object.Exception; - Exception thrown when the writer is given data that would result in invalid XML.
- alias
EmptyTag
= std.typecons.Flag!"EmptyTag
".Flag; - std.typecons.Flag indicating whether closeStartTag or writeStartTag or will write an empty element tag (which then does not require a corresponding end tag).
- alias
Newline
= std.typecons.Flag!"Newline
".Flag; - std.typecons.Flag indicating whether a write function of XMLWriter will write a newline followed by an indent before the entity being written.
- alias
InsertIndent
= std.typecons.Flag!"InsertIndent
".Flag; - std.typecons.Flag indicating whether a write function of XMLWriter which accepts text which may include newlines will write an indent after each newline is written.
- struct
XMLWriter
(OR) if (isOutputRange!(OR, char)); autoxmlWriter
(OR)(OR output, string baseIndent = " "); - Writes XML to an output range of characters.Note that default initialization, copying, and assignment are disabled for
XMLWriter
. This is becauseXMLWriter
is essentially a reference type, but in many cases, it doesn't need to be passed around, and forcing it to be allocated on the heap in order to be a reference type seemed like an unnecessary heap allocation. So, it's a struct with default initialization, copying, and assignment disabled so that like a reference type, it will not be copied or overwritten. Code that needs to pass it around can pass it by ref or use the constructor to explicitly allocate it on the heap and then pass around the resulting pointer. The optional Newline and InsertIndent parameters to the various write functions are used to control the formatting of the XML, and writeIndent and output can be used for additional control over the formatting. The indent provided to theXMLWriter
is the base indent that will be used whenever writeIndent and any write functions using Newline.yes or InsertIndent.yes are called - e.g. if the base indent is 4 spaces, tagDepth == 3, and Newline.yes is passed to writeComment, then a newline followed by 12 spaces will be written to the output range after the comment. writeXMLDecl can be used to write the <?xml...?> declaration to the output range before constructing an XML writer, but if an application wishes to do anything with a DTD section, it will have to write that to the output range on its own before constructing theXMLWriter
.XMLWriter
expects to start writing XML after any <?xml...?> or <!DOCTYPE...> declarations. The write functions check the arguments prior to writing anything to the output range, so theXMLWriter
is not in an invalid state after an XMLWritingException is thrown, but it is in an invalid state if any other exception is thrown (which will only occur if an input range that is passed to a write function throws or if the ouput range throws whenXMLWriter
calls put on it).Parameters:OR output The output range that the XML will be written to. string baseIndent Optional argument indicating the base indent to be used when an indent is inserted after a newline in the XML (with the actual indent being the base indent inserted once for each level of the tagDepth). The default is four spaces. baseIndent may only contain spaces and/or tabs. See Also: writeXMLDecl
dxml.util.encodeAttr
dxml.util.encodeText
dxml.util.StdEntityRef
dxml.util.toCharRefExamples:import std.array : appender; { auto writer = xmlWriter(appender!string()); writer.writeStartTag("root"); writer.openStartTag("foo"); writer.writeAttr("a", "42"); writer.closeStartTag(); writer.writeText("bar"); writer.writeEndTag("foo"); writer.writeEndTag("root"); assert(writer.output.data == "\n" ~ "<root>\n" ~ ` <foo a="42">` ~ "\n" ~ " bar\n" ~ " </foo>\n" ~ "</root>"); } // Newline.no can be used to avoid inserting newlines. { auto writer = xmlWriter(appender!string()); // Unless writeXMLDecl was used, Newline.no is needed on the first // entity to avoid having the document start with a newline. writer.writeStartTag("root", Newline.no); writer.openStartTag("foo"); writer.writeAttr("a", "42"); writer.closeStartTag(); writer.writeText("bar", Newline.no); writer.writeEndTag("foo", Newline.no); writer.writeEndTag("root"); assert(writer.output.data == "<root>\n" ~ ` <foo a="42">bar</foo>` ~ "\n" ~ "</root>"); }
- void
openStartTag
(string name, Newline newline = Newline.yes); - Writes the first portion of a start tag to the given output range.Once
openStartTag
has been called, writeAttr can be called to add attributes to the start tag. closeStartTag writes the closing portion of the start tag. OnceopenStartTag
has been called, it is an error to call any function on XMLWriter other than closeStartTag, writeAttr, writeIndent, tagDepth, baseIndent, or output until closeStartTag has been called (basically, any function that involves writing XML that is not legal in a start tag can't be called until the start tag has been properly closed). It is also an error to callopenStartTag
after the end tag for the root element has been written.Parameters:string name The name of the start tag. Newline newline Whether a newline followed by an indent will be written to the output range before the start tag. Throws: XMLWritingException if the given name is not a valid XML tag name. - void
writeAttr
(char quote = '"', R)(string name, R value, Newline newline = Newline.no)
if((quote == '"' || quote == '\'') && isForwardRange!R && isSomeChar!(ElementType!R)); - Writes an attribute for a start tag to the output range.Parameters:
quote The quote character to use for the attribute value's delimiter. string name The name of the attribute. R value The value of the attribute. Newline newline Whether a newline followed by an indent will be written to the output range before the attribute. Note that unlike most write functions, the default is Newline.no (since it's more common to not want newlines between attributes). Throws: XMLWritingException if the given name is not a valid XML attribute name, if the given value is not a valid XML attribute value, or if the given name has already been written to the current start tag. dxml.util.encodeAttr can be used to encode any characters that are not legal in their literal form in an attribute value but are legal as entity references.See Also: dxml.util.encodeAttr
dxml.util.StdEntityRef
dxml.util.toCharRef
http://www.w3.org/TR/REC-xml/#NT-AttributeExamples:import std.array : appender; import std.exception : assertThrown; import dxml.util : encodeAttr; auto writer = xmlWriter(appender!string()); writer.openStartTag("root", Newline.no); assert(writer.output.data == "<root"); writer.writeAttr("a", "one"); assert(writer.output.data == `<root a="one"`); writer.writeAttr("b", "two"); assert(writer.output.data == `<root a="one" b="two"`); // It's illegal for two attributes on the same start tag // to have the same name. assertThrown!XMLWritingException(writer.writeAttr("a", "three")); // Invalid name. assertThrown!XMLWritingException(writer.writeAttr("=", "value")); // Can't have a quote that matches the enclosing quote. assertThrown!XMLWritingException(writer.writeAttr("c", `foo"bar`)); assertThrown!XMLWritingException(writer.writeAttr!'\''("c", "foo'bar")); // Unchanged after an XMLWritingException is thrown. assert(writer.output.data == `<root a="one" b="two"`); writer.closeStartTag(); assert(writer.output.data == `<root a="one" b="two">`); writer.openStartTag("foobar"); assert(writer.output.data == `<root a="one" b="two">` ~ "\n" ~ " <foobar"); // " is the default for the quote character, but ' can be specified. writer.writeAttr!'\''("answer", "42"); assert(writer.output.data == `<root a="one" b="two">` ~ "\n" ~ " <foobar answer='42'"); writer.writeAttr("base", "13", Newline.yes); assert(writer.output.data == `<root a="one" b="two">` ~ "\n" ~ " <foobar answer='42'\n" ~ ` base="13"`); writer.closeStartTag(); assert(writer.output.data == `<root a="one" b="two">` ~ "\n" ~ " <foobar answer='42'\n" ~ ` base="13">`); writer.openStartTag("tag"); assert(writer.output.data == `<root a="one" b="two">` ~ "\n" ~ " <foobar answer='42'\n" ~ ` base="13">` ~ "\n" ~ " <tag"); // &, <, and > are not legal in an attribute value. assertThrown!XMLWritingException(writer.writeAttr("foo", "&")); // Unchanged after an XMLWritingException is thrown. assert(writer.output.data == `<root a="one" b="two">` ~ "\n" ~ " <foobar answer='42'\n" ~ ` base="13">` ~ "\n" ~ " <tag"); // Use dxml.util.encodeAttr to encode characters that aren't // legal in an attribute value but can legally be encoded. writer.writeAttr("foo", encodeAttr("&")); assert(writer.output.data == `<root a="one" b="two">` ~ "\n" ~ " <foobar answer='42'\n" ~ ` base="13">` ~ "\n" ~ ` <tag foo="&"`); writer.closeStartTag(EmptyTag.yes); assert(writer.output.data == `<root a="one" b="two">` ~ "\n" ~ " <foobar answer='42'\n" ~ ` base="13">` ~ "\n" ~ ` <tag foo="&"/>`); writer.writeEndTag(); writer.writeEndTag(); assert(writer.output.data == `<root a="one" b="two">` ~ "\n" ~ " <foobar answer='42'\n" ~ ` base="13">` ~ "\n" ~ ` <tag foo="&"/>` ~ "\n" ~ " </foobar>\n" ~ "</root>");
- void
closeStartTag
(EmptyTag emptyTag = EmptyTag.no); - Writes the end of a start tag to the ouput range.It is an error to call
closeStartTag
unless a start tag has been opened and not yet closed.Parameters:EmptyTag emptyTag Whether the start tag will be empty (i.e. terminated with "/>" so that there is no corresponding end tag). Examples:import std.array : appender; auto writer = xmlWriter(appender!string()); writer.openStartTag("root", Newline.no); assert(writer.output.data == "<root"); writer.closeStartTag(); assert(writer.output.data == "<root>"); writer.openStartTag("foo"); assert(writer.output.data == "<root>\n" ~ " <foo"); writer.closeStartTag(EmptyTag.yes); assert(writer.output.data == "<root>\n" ~ " <foo/>"); writer.writeEndTag(); assert(writer.output.data == "<root>\n" ~ " <foo/>\n" ~ "</root>");
- void
writeStartTag
(string name, EmptyTag emptyTag = EmptyTag.no, Newline newline = Newline.yes); voidwriteStartTag
(string name, Newline newline, EmptyTag emptyTag = EmptyTag.no); - Writes a start tag with no attributes.This is equivalent to calling openStartTag immediately followed by closeStartTag. It is an error to call
writeStartTag
after the end tag for the root element has been written.Parameters:string name The name of the start tag. EmptyTag emptyTag Whether the start tag will be empty (i.e. terminated with "/>" so that there is no corresponding end tag). Newline newline Whether a newline followed by an indent will be written to the output range before the start tag. Throws: XMLWritingException if the given name is not a valid XML tag name. - void
writeEndTag
(string name, Newline newline = Newline.yes); voidwriteEndTag
(Newline newline = Newline.yes); - Writes an end tag to the output range with the name of the start tag that was most recently written and does not yet have a matching end tag.If a name is provided, then it will be validated against the matching start tag.Parameters:
string name Name to check against the matching start tag. Newline newline Whether a newline followed by an indent will be written to the output range before the end tag. Throws: XMLWritingException if no start tag is waiting for a matching end tag or if the given name does not match the name of the start tag that needs to be matched next.See Also: openStartTag
writeAttr
closeStartTag
writeEndTag">writeEndTag
writeTaggedText
http://www.w3.org/TR/REC-xml/#NT-ETagExamples:import std.array : appender; import std.exception : assertThrown; auto writer = xmlWriter(appender!string()); writer.writeStartTag("root", Newline.no); assert(writer.output.data == "<root>"); writer.writeStartTag("foo"); assert(writer.output.data == "<root>\n" ~ " <foo>"); // Name doesn't match start tag, which is <foo>. assertThrown!XMLWritingException(writer.writeEndTag("bar")); // Unchanged after an XMLWritingException is thrown. assert(writer.output.data == "<root>\n" ~ " <foo>"); writer.writeEndTag("foo", Newline.no); assert(writer.output.data == "<root>\n" ~ " <foo></foo>"); writer.writeStartTag("bar"); assert(writer.output.data == "<root>\n" ~ " <foo></foo>\n" ~ " <bar>"); writer.writeEndTag("bar"); assert(writer.output.data == "<root>\n" ~ " <foo></foo>\n" ~ " <bar>\n" ~ " </bar>"); // No name is required, but if it is not provided, then the code cannot // validate that it's writing the end tag that it thinks it's writing. writer.writeEndTag(); assert(writer.output.data == "<root>\n" ~ " <foo></foo>\n" ~ " <bar>\n" ~ " </bar>\n" ~ "</root>");
- void
writeText
(R)(R text, Newline newline = Newline.yes, InsertIndent insertIndent = InsertIndent.yes)
if(isForwardRange!R && isSomeChar!(ElementType!R)); voidwriteText
(R)(R text, InsertIndent insertIndent, Newline newline = Newline.yes)
if(isForwardRange!R && isSomeChar!(ElementType!R)); - This writes the text that goes between start tags and end tags.It can be called multiple times in a row, and the given text will just end up being appended to the current text field. It is an error to call
writeText
after the end tag for the root element has been written.Parameters:R text The text to write. Newline newline Whether a newline followed by an indent will be written to the output range before the text. It will not include an indent if insertIndent == InsertIndent.no. InsertIndent insertIndent Whether an indent will be inserted after each newline within the text. Throws: XMLWritingException if any characters or sequence of characters in the given text are not legal in the text portion of an XML document. dxml.util.encodeText can be used to encode any characters that are not legal in their literal form but are legal as entity references. - void
writeComment
(R)(R text, Newline newline = Newline.yes, InsertIndent insertIndent = InsertIndent.yes)
if(isForwardRange!R && isSomeChar!(ElementType!R)); voidwriteComment
(R)(R text, InsertIndent insertIndent, Newline newline = Newline.yes)
if(isForwardRange!R && isSomeChar!(ElementType!R)); - Writes a comment to the output range.Parameters:
R text The text of the comment. Newline newline Whether a newline followed by an indent will be written to the output range before the comment tag. InsertIndent insertIndent Whether an indent will be inserted after each newline within the text. See Also: http://www.w3.org/TR/REC-xml/#NT-CommentExamples:import std.array : appender; import std.exception : assertThrown; auto writer = xmlWriter(appender!string()); writer.writeComment(" And so it begins... ", Newline.no); writer.writeStartTag("root"); writer.writeComment("A comment"); writer.writeComment("Another comment"); writer.writeComment("No preceding newline", Newline.no); writer.writeComment("A comment\nwith a newline"); writer.writeComment("Another newline\nbut no indent", InsertIndent.no); writer.writeStartTag("tag"); writer.writeComment("Deeper comment"); writer.writeEndTag("tag"); writer.writeEndTag("root"); writer.writeComment(" And so it ends... "); assert(writer.output.data == "<!-- And so it begins... -->\n" ~ "<root>\n" ~ " <!--A comment-->\n" ~ " <!--Another comment--><!--No preceding newline-->\n" ~ " <!--A comment\n" ~ " with a newline-->\n" ~ " <!--Another newline\n" ~ "but no indent-->\n" ~ " <tag>\n" ~ " <!--Deeper comment-->\n" ~ " </tag>\n" ~ "</root>\n" ~ "<!-- And so it ends... -->"); // -- is not legal in an XML comment. assertThrown!XMLWritingException(writer.writeComment("foo--bar")); // - is not legal at the end of an XML comment. assertThrown!XMLWritingException(writer.writeComment("foo-")); // Unchanged after an XMLWritingException is thrown. assert(writer.output.data == "<!-- And so it begins... -->\n" ~ "<root>\n" ~ " <!--A comment-->\n" ~ " <!--Another comment--><!--No preceding newline-->\n" ~ " <!--A comment\n" ~ " with a newline-->\n" ~ " <!--Another newline\n" ~ "but no indent-->\n" ~ " <tag>\n" ~ " <!--Deeper comment-->\n" ~ " </tag>\n" ~ "</root>\n" ~ "<!-- And so it ends... -->");
- void
writeCDATA
(R)(R text, Newline newline = Newline.yes, InsertIndent insertIndent = InsertIndent.yes)
if(isForwardRange!R && isSomeChar!(ElementType!R)); voidwriteCDATA
(R)(R text, InsertIndent insertIndent, Newline newline = Newline.yes)
if(isForwardRange!R && isSomeChar!(ElementType!R)); - Writes a <![CDATA[...]]> section with the given text between the brackets.Parameters:
R text The text of the CDATA section. Newline newline Whether a newline followed by an indent will be written to the output range before the cdata section. InsertIndent insertIndent Whether an indent will be inserted after each newline within the text. See Also: http://www.w3.org/TR/REC-xml/#NT-CDSectExamples:import std.array : appender; import std.exception : assertThrown; auto writer = xmlWriter(appender!string()); writer.writeStartTag("root", Newline.no); writer.writeCDATA("see data run"); writer.writeCDATA("More data"); writer.writeCDATA("No preceding newline", Newline.no); writer.writeCDATA("some data\nwith a newline"); writer.writeCDATA("Another newline\nbut no indent", InsertIndent.no); writer.writeStartTag("tag"); writer.writeCDATA(" Deeper data <><> "); writer.writeEndTag("tag"); writer.writeEndTag("root"); assert(writer.output.data == "<root>\n" ~ " <![CDATA[see data run]]>\n" ~ " <![CDATA[More data]]><![CDATA[No preceding newline]]>\n" ~ " <![CDATA[some data\n" ~ " with a newline]]>\n" ~ " <![CDATA[Another newline\n" ~ "but no indent]]>\n" ~ " <tag>\n" ~ " <![CDATA[ Deeper data <><> ]]>\n" ~ " </tag>\n" ~ "</root>"); // ]]> is not legal in a CDATA section. assertThrown!XMLWritingException(writer.writeCDATA("]]>")); // Unchanged after an XMLWritingException is thrown. assert(writer.output.data == "<root>\n" ~ " <![CDATA[see data run]]>\n" ~ " <![CDATA[More data]]><![CDATA[No preceding newline]]>\n" ~ " <![CDATA[some data\n" ~ " with a newline]]>\n" ~ " <![CDATA[Another newline\n" ~ "but no indent]]>\n" ~ " <tag>\n" ~ " <![CDATA[ Deeper data <><> ]]>\n" ~ " </tag>\n" ~ "</root>");
- void
writePI
(R)(R name, Newline newline = Newline.yes)
if(isForwardRange!R && isSomeChar!(ElementType!R)); voidwritePI
(R1, R2)(R1 name, R2 text, Newline newline = Newline.yes, InsertIndent insertIndent = InsertIndent.yes)
if(isForwardRange!R1 && isSomeChar!(ElementType!R1) && isForwardRange!R2 && isSomeChar!(ElementType!R2)); voidwritePI
(R1, R2)(R1 name, R2 text, InsertIndent insertIndent, Newline newline = Newline.yes)
if(isForwardRange!R1 && isSomeChar!(ElementType!R1) && isForwardRange!R2 && isSomeChar!(ElementType!R2)); - Writes a parsing instruction to the output range.Parameters:
R name The name of the parsing instruction. R2 text The text of the parsing instruction. Newline newline Whether a newline followed by an indent will be written to the output range before the processing instruction. InsertIndent insertIndent Whether an indent will be inserted after each newline within the text. Throws: XMLWritingException if the given name or text is not legal in an XML processing instruction.See Also: http://www.w3.org/TR/REC-xml/#NT-PIExamples:import std.array : appender; import std.exception : assertThrown; auto writer = xmlWriter(appender!string()); writer.writePI("pi", Newline.no); writer.writeStartTag("root"); writer.writePI("Poirot", "has a cane"); writer.writePI("Sherlock"); writer.writePI("No", "preceding newline", Newline.no); writer.writePI("Ditto", Newline.no); writer.writePI("target", "some data\nwith a newline"); writer.writePI("name", "Another newline\nbut no indent", InsertIndent.no); writer.writeStartTag("tag"); writer.writePI("Deep", "Thought"); writer.writeEndTag("tag"); writer.writeEndTag("root"); assert(writer.output.data == "<?pi?>\n" ~ "<root>\n" ~ " <?Poirot has a cane?>\n" ~ " <?Sherlock?><?No preceding newline?><?Ditto?>\n" ~ " <?target some data\n" ~ " with a newline?>\n" ~ " <?name Another newline\n" ~ "but no indent?>\n" ~ " <tag>\n" ~ " <?Deep Thought?>\n" ~ " </tag>\n" ~ "</root>"); // The name xml (no matter the casing) is illegal as a name for // processing instructions (so that it can't be confused for the // optional <?xml...> declaration at the top of an XML document). assertThrown!XMLWritingException(writer.writePI("xml", "bar")); // ! is not legal in a processing instruction's name. assertThrown!XMLWritingException(writer.writePI("!", "bar")); // ?> is not legal in a processing instruction. assertThrown!XMLWritingException(writer.writePI("foo", "?>")); // Unchanged after an XMLWritingException is thrown. assert(writer.output.data == "<?pi?>\n" ~ "<root>\n" ~ " <?Poirot has a cane?>\n" ~ " <?Sherlock?><?No preceding newline?><?Ditto?>\n" ~ " <?target some data\n" ~ " with a newline?>\n" ~ " <?name Another newline\n" ~ "but no indent?>\n" ~ " <tag>\n" ~ " <?Deep Thought?>\n" ~ " </tag>\n" ~ "</root>");
- const pure nothrow @nogc @property @safe int
tagDepth
(); - The current depth of the tag stack.Examples:
import std.array : appender; auto writer = xmlWriter(appender!string()); assert(writer.tagDepth == 0); writer.writeStartTag("root", Newline.no); assert(writer.tagDepth == 1); assert(writer.output.data == "<root>"); writer.writeStartTag("a"); assert(writer.tagDepth == 2); assert(writer.output.data == "<root>\n" ~ " <a>"); // The tag depth is increased as soon as a start tag is opened, so // any calls to writeIndent or writeAttr while a start tag is open // will use the same tag depth as the children of the start tag. writer.openStartTag("b"); assert(writer.tagDepth == 3); assert(writer.output.data == "<root>\n" ~ " <a>\n" ~ " <b"); writer.closeStartTag(); assert(writer.tagDepth == 3); assert(writer.output.data == "<root>\n" ~ " <a>\n" ~ " <b>"); writer.writeEndTag("b"); assert(writer.tagDepth == 2); assert(writer.output.data == "<root>\n" ~ " <a>\n" ~ " <b>\n" ~ " </b>"); // Only start tags and end tags affect the tag depth. writer.writeComment("comment"); assert(writer.tagDepth == 2); assert(writer.output.data == "<root>\n" ~ " <a>\n" ~ " <b>\n" ~ " </b>\n" ~ " <!--comment-->"); writer.writeEndTag("a"); assert(writer.tagDepth == 1); assert(writer.output.data == "<root>\n" ~ " <a>\n" ~ " <b>\n" ~ " </b>\n" ~ " <!--comment-->\n" ~ " </a>"); writer.writeEndTag("root"); assert(writer.tagDepth == 0); assert(writer.output.data == "<root>\n" ~ " <a>\n" ~ " <b>\n" ~ " </b>\n" ~ " <!--comment-->\n" ~ " </a>\n" ~ "</root>");
- const pure nothrow @nogc @property @safe string
baseIndent
(); - The text that will be written for each level of the tag depth when an indent is written.Examples:
import std.array : appender; { auto writer = xmlWriter(appender!string()); assert(writer.baseIndent == " "); } { auto writer = xmlWriter(appender!string(), " "); assert(writer.baseIndent == " "); } { auto writer = xmlWriter(appender!string(), "\t"); assert(writer.baseIndent == "\t"); }
- void
writeIndent
(); - Writes a newline followed by an indent to the output range.In general, the various write functions already provide this functionality via their Newline parameter, but there may be cases where it is desirable to insert a newline independently of calling a write function. If arbitrary whitespace needs to be inserted, then output can be used to get at the output range so that it can be written to directly.Examples:
import std.array : appender; auto writer = xmlWriter(appender!string()); writer.writeStartTag("root", Newline.no); assert(writer.output.data == "<root>"); writer.writeIndent(); assert(writer.output.data == "<root>\n" ~ " "); writer.writeStartTag("foo"); assert(writer.output.data == "<root>\n" ~ " \n" ~ " <foo>"); writer.writeIndent(); assert(writer.output.data == "<root>\n" ~ " \n" ~ " <foo>\n" ~ " "); writer.writeText("some text"); assert(writer.output.data == "<root>\n" ~ " \n" ~ " <foo>\n" ~ " \n" ~ " some text"); writer.writeIndent(); assert(writer.output.data == "<root>\n" ~ " \n" ~ " <foo>\n" ~ " \n" ~ " some text\n" ~ " "); writer.writeEndTag(); writer.writeEndTag(); assert(writer.output.data == "<root>\n" ~ " \n" ~ " <foo>\n" ~ " \n" ~ " some text\n" ~ " \n" ~ " </foo>\n" ~ "</root>");
- pure nothrow @nogc @property ref @safe auto
output
(); - Provides access to the output range that's used by XMLWriter.Note that any is data written to the output range without using XMLWriter could result in invalid XML. This property is here primarily to provide easy access to the
output
range when XMLWriter is done writing (e.g. to get at its data member if it's a std.array.Appender), but programs can use it to write other data (such as whitespace other than the indent) to theoutput
range while XMLWriter is still writing so long as it's understood that unlike when the XMLWriter's write functions are called, calling put on theoutput
range directly is unchecked and therefore does risk making the XML invalid. Also, depending on the type of the output range, copying it will cause problems (e.g. if it's not a reference type, writing to a copy may not write to the output range inside of XMLWriter), So in general, if the output range is going to be written to, it should be written to by usingoutput
directly rather than assigning it to a variable. - this(OR output, string baseIndent = " ");
- In general, it's more user-friendly to use xmlWriter rather than calling the constructor directly, because then the type of the output range can be inferred. However, in the case where a pointer is desirable, then the constructor needs to be called instead of xmlWriter.Parameters:
OR output The output range that the XML will be written to. string baseIndent Optional argument indicating the base indent to be used when an indent is inserted after a newline in the XML (with the actual indent being the base indent inserted once for each level of the tagDepth). The default is four spaces. See Also: xmlWriterExamples:import std.array : Appender, appender; auto writer = new XMLWriter!(Appender!string)(appender!string()); writer.writeStartTag("root", Newline.no, EmptyTag.yes); assert(writer.output.data == "<root/>");
- void
writeXMLDecl
(S, OR)(ref OR output)
if(isOutputRange!(OR, char) && isSomeString!S); - Writes the <?xml...?> declaration to the given output range. If it's going to be used in conjunction with XMLWriter, then either
writeXMLDecl
will need to be called before constructing the XMLWriter, or XMLWriter.output will need to be used to write to the output range before writing anything else using the XMLWriter. XMLWriter expects to be writing XML after the <?xml...?> and <!DOCTYPE...> declarations (assuming they're present at all), and it is invalid to put a <?xml...?> declaration anywhere but at the very beginning of an XML document.Parameters:S The string type used to infer the encoding type. Ideally, it would be inferred from the type of the output range, but unfortunately, the output range API does not provide that functionality. If S does not match the encoding of the output range, then the result will be invalid XML. OR output The output range to write to. Examples:import std.array : appender; { auto app = appender!string(); app.writeXMLDecl!string(); assert(app.data == `<?xml version="1.0" encoding="UTF-8"?>`); } { auto app = appender!wstring(); app.writeXMLDecl!wstring(); assert(app.data == `<?xml version="1.0" encoding="UTF-16"?>`w); } { auto app = appender!dstring(); app.writeXMLDecl!dstring(); assert(app.data == `<?xml version="1.0" encoding="UTF-32"?>`d); } // This would be invalid XML, because the output range contains UTF-8, but // writeXMLDecl is told to write that the encoding is UTF-32. { auto app = appender!string(); app.writeXMLDecl!dstring(); assert(app.data == `<?xml version="1.0" encoding="UTF-32"?>`); }
- void
writeTaggedText
(XW, R)(ref XW writer, string name, R text, Newline newline = Newline.yes, InsertIndent insertIndent = InsertIndent.yes)
if(isInstanceOf!(XMLWriter, XW) && isForwardRange!R && isSomeChar!(ElementType!R)); voidwriteTaggedText
(XW, R)(ref XW writer, string name, R text, InsertIndent insertIndent, Newline newline = Newline.yes)
if(isInstanceOf!(XMLWriter, XW) && isForwardRange!R && isSomeChar!(ElementType!R)); - Helper function for writing text which has a start tag and end tag on each side and no attributes so that it can be done with one function call instead of three.
writeTaggedText
is essentially equivalent to callingwriter.writeStartTag(name, newline); writer.writeText(text, insertIndent, Newline.no); writer.writeEndTag(Newline.no);
with the difference being that both the name and text are validated before any data is written. So, if the text is invalid XML, then nothing will have been written to the output range when the exception is thrown (whereas if each function were called individually, then the start tag would have been written before the exception was thrown from writeText). If more control is needed over the formatting, or if attributes are needed on the start tag, then the functions will have to be called separately instead of callingwriteTaggedText
.Parameters:XW writer The XMLWriter to write to. string name The name of the start tag. R text The text to write between the start and end tags. Newline newline Whether a newline followed by an indent will be written to the output range before the start tag. InsertIndent insertIndent Whether an indent will be inserted after each newline within the text. Throws: XMLWritingException if the given name is an invalid XML tag name or if the given text contains any characters or sequence of characters which are not legal in the text portion of an XML document. dxml.util.encodeText can be used to encode any characters that are not legal in their literal form in the text but are legal as entity references.Examples:import std.array : appender; { auto writer = xmlWriter(appender!string()); writer.writeStartTag("root", Newline.no); writer.writeTaggedText("foo", "Some text between foos"); writer.writeEndTag("root"); assert(writer.output.data == "<root>\n" ~ " <foo>Some text between foos</foo>\n" ~ "</root>"); } // With Newline.no { auto writer = xmlWriter(appender!string()); writer.writeStartTag("root", Newline.no); writer.writeTaggedText("foo", "Some text between foos", Newline.no); writer.writeEndTag("root"); assert(writer.output.data == "<root><foo>Some text between foos</foo>\n" ~ "</root>"); } // With InsertIndent.yes { auto writer = xmlWriter(appender!string()); writer.writeStartTag("root", Newline.no); writer.writeTaggedText("foo", "Some text\nNext line"); writer.writeEndTag("root"); assert(writer.output.data == "<root>\n" ~ " <foo>Some text\n" ~ " Next line</foo>\n" ~ "</root>"); } // With InsertIndent.no { auto writer = xmlWriter(appender!string()); writer.writeStartTag("root", Newline.no); writer.writeTaggedText("foo", "Some text\nNext line", InsertIndent.no); writer.writeEndTag("root"); assert(writer.output.data == "<root>\n" ~ " <foo>Some text\n" ~ "Next line</foo>\n" ~ "</root>"); }