class LibXML::XML::Writer
The XML::Writer class provides a simpler, alternative way to build a valid XML document from scratch (forward-only) compared to a DOM approach (based on XML::Document class).
For a more in depth tutorial, albeit in C, see xmlsoft.org/xmlwriter.html
Public Class Methods
Creates a XML::Writer which will write into an in memory XML::Document
static VALUE rxml_writer_doc(VALUE klass)
{
xmlDocPtr doc;
rxml_writer_object* rwo;
rwo = ALLOC(rxml_writer_object);
rwo->buffer = NULL;
rwo->output = Qnil;
rwo->closed = 0;
rwo->encoding = rb_utf8_encoding();
rwo->output_type = RXMLW_OUTPUT_DOC;
if (NULL == (rwo->writer = xmlNewTextWriterDoc(&doc, 0)))
{
rxml_raise(xmlGetLastError());
}
rwo->output = rxml_document_wrap(doc);
return rxml_writer_wrap(rwo);
}
Creates a XML::Writer object which will write XML into the file with the given name.
static VALUE rxml_writer_file(VALUE klass, VALUE filename)
{
rxml_writer_object* rwo;
rwo = ALLOC(rxml_writer_object);
rwo->output = Qnil;
rwo->buffer = NULL;
rwo->closed = 0;
rwo->encoding = rb_utf8_encoding();
rwo->output_type = RXMLW_OUTPUT_NONE;
if (NULL == (rwo->writer = xmlNewTextWriterFilename(StringValueCStr(filename), 0)))
{
rxml_raise(xmlGetLastError());
}
return rxml_writer_wrap(rwo);
}
Creates a XML::Writer which will write XML directly into an IO object.
static VALUE rxml_writer_io(VALUE klass, VALUE io)
{
xmlOutputBufferPtr out;
rxml_writer_object* rwo;
rwo = ALLOC(rxml_writer_object);
rwo->output = io;
rwo->buffer = NULL;
rwo->closed = 0;
rwo->encoding = rb_enc_get(io);
if (!rwo->encoding)
rwo->encoding = rb_utf8_encoding();
rwo->output_type = RXMLW_OUTPUT_IO;
xmlCharEncodingHandlerPtr encodingHdlr = xmlFindCharEncodingHandler(rwo->encoding->name);
if (NULL == (out = xmlOutputBufferCreateIO(rxml_writer_write_callback, NULL, (void*)rwo, encodingHdlr)))
{
rxml_raise(xmlGetLastError());
}
if (NULL == (rwo->writer = xmlNewTextWriter(out)))
{
rxml_raise(xmlGetLastError());
}
return rxml_writer_wrap(rwo);
}
Creates a XML::Writer which will write XML into memory, as string.
static VALUE rxml_writer_string(VALUE klass)
{
rxml_writer_object* rwo;
rwo = ALLOC(rxml_writer_object);
rwo->output = Qnil;
rwo->closed = 0;
rwo->encoding = rb_utf8_encoding();
rwo->output_type = RXMLW_OUTPUT_STRING;
if (NULL == (rwo->buffer = xmlBufferCreate()))
{
rxml_raise(xmlGetLastError());
}
if (NULL == (rwo->writer = xmlNewTextWriterMemory(rwo->buffer, 0)))
{
xmlBufferFree(rwo->buffer);
rxml_raise(xmlGetLastError());
}
return rxml_writer_wrap(rwo);
}
Public Instance Methods
Ends an attribute, namespaced or not. Returns false on failure.
static VALUE rxml_writer_end_attribute(VALUE self)
{
return numeric_rxml_writer_void(self, xmlTextWriterEndAttribute);
}
Ends current CDATA section. Returns false on failure.
static VALUE rxml_writer_end_cdata(VALUE self)
{
return numeric_rxml_writer_void(self, xmlTextWriterEndCDATA);
}
Ends current comment, returns false on failure. Note: libxml2 >= 2.6.7 required
static VALUE rxml_writer_end_comment(VALUE self)
{
return numeric_rxml_writer_void(self, xmlTextWriterEndComment);
}
Ends current document. Returns false on failure.
static VALUE rxml_writer_end_document(VALUE self)
{
return numeric_rxml_writer_void(self, xmlTextWriterEndDocument);
}
Ends current DTD, returns false on failure.
static VALUE rxml_writer_end_dtd(VALUE self)
{
return numeric_rxml_writer_void(self, xmlTextWriterEndDTD);
}
Ends current DTD attribute list, returns false on failure.
static VALUE rxml_writer_end_dtd_attlist(VALUE self)
{
return numeric_rxml_writer_void(self, xmlTextWriterEndDTDAttlist);
}
Ends current DTD element, returns false on failure.
static VALUE rxml_writer_end_dtd_element(VALUE self)
{
return numeric_rxml_writer_void(self, xmlTextWriterEndDTDElement);
}
Ends current DTD entity, returns false on failure.
static VALUE rxml_writer_end_dtd_entity(VALUE self)
{
return numeric_rxml_writer_void(self, xmlTextWriterEndDTDEntity);
}
Ends current element, namespaced or not. Returns false on failure.
static VALUE rxml_writer_end_element(VALUE self)
{
return numeric_rxml_writer_void(self, xmlTextWriterEndElement);
}
Ends current processing instruction. Returns false on failure.
static VALUE rxml_writer_end_pi(VALUE self)
{
return numeric_rxml_writer_void(self, xmlTextWriterEndPI);
}
Flushes the output buffer. Returns the number of written bytes or the current content of the internal buffer for a in memory XML::Writer. If empty? is true, and for a in memory XML::Writer, this internel buffer is empty.
static VALUE rxml_writer_flush(int argc, VALUE* argv, VALUE self)
{
int ret;
VALUE empty;
rxml_writer_object* rwo;
rb_scan_args(argc, argv, "01", &empty);
rwo = rxml_textwriter_get(self);
if (-1 == (ret = xmlTextWriterFlush(rwo->writer)))
{
rxml_raise(xmlGetLastError());
}
if (NULL != rwo->buffer)
{
VALUE content;
content = rb_external_str_new_with_enc((const char*)rwo->buffer->content, rwo->buffer->use, rwo->encoding);
if (NIL_P(empty) || RTEST(empty))
{ /* nil = default value = true */
xmlBufferEmpty(rwo->buffer);
}
return content;
}
else
{
return INT2NUM(ret);
}
}
Ends current element, namespaced or not. Returns false on failure. This method writes an end tag even if the element is empty (<foo></foo>), end_element does not (<foo/>).
static VALUE rxml_writer_full_end_element(VALUE self)
{
return numeric_rxml_writer_void(self, xmlTextWriterFullEndElement);
}
Returns the associated result object to the XML::Writer creation. A String for a XML::Writer object created with XML::Writer::string, a XML::Document with XML::Writer::document, etc.
static VALUE rxml_writer_result(VALUE self)
{
VALUE ret = Qnil;
rxml_writer_object* rwo = rxml_textwriter_get(self);
int bytesWritten = xmlTextWriterFlush(rwo->writer);
if (bytesWritten == -1)
{
rxml_raise(xmlGetLastError());
}
switch (rwo->output_type)
{
case RXMLW_OUTPUT_DOC:
ret = rwo->output;
break;
case RXMLW_OUTPUT_STRING:
ret = rb_external_str_new_with_enc((const char*)rwo->buffer->content, rwo->buffer->use, rwo->encoding);
break;
case RXMLW_OUTPUT_IO:
case RXMLW_OUTPUT_NONE:
break;
default:
rb_bug("unexpected output");
break;
}
return ret;
}
Toggles indentation on or off. Returns false on failure.
Availability: libxml2 >= 2.6.5
static VALUE rxml_writer_set_indent(VALUE self, VALUE indentation)
{
int ret;
rxml_writer_object* rwo;
rwo = rxml_textwriter_get(self);
ret = xmlTextWriterSetIndent(rwo->writer, RTEST(indentation));
return (-1 == ret ? Qfalse : Qtrue);
}
Sets the string to use to indent each element of the document. Don’t forget to enable indentation with set_indent. Returns false on failure.
Availability: libxml2 >= 2.6.5
static VALUE rxml_writer_set_indent_string(VALUE self, VALUE indentation)
{
return numeric_rxml_writer_string(self, indentation, xmlTextWriterSetIndentString);
}
Sets the character used to quote attributes. Returns false on failure.
Notes:
-
only “ (default) and ‘ characters are valid
-
availability: libxml2 >= 2.9.0
static VALUE rxml_writer_set_quote_char(VALUE self, VALUE quotechar)
{
int ret;
const char* xquotechar;
rxml_writer_object* rwo;
rwo = rxml_textwriter_get(self);
xquotechar = StringValueCStr(quotechar);
ret = xmlTextWriterSetQuoteChar(rwo->writer, (xmlChar)xquotechar[0]);
return (-1 == ret ? Qfalse : Qtrue);
}
Starts an attribute. Returns false on failure.
static VALUE rxml_writer_start_attribute(VALUE self, VALUE name)
{
return numeric_rxml_writer_string(self, name, xmlTextWriterStartAttribute);
}
Starts a namespaced attribute. Returns false on failure.
Note: by default, the xmlns: definition is repeated on every element. If you want the prefix, but don’t want the xmlns: declaration repeated, set namespaceURI to nil or omit it. Don’t forget to declare the namespace prefix somewhere earlier.
static VALUE rxml_writer_start_attribute_ns(int argc, VALUE* argv, VALUE self)
{
VALUE prefix, name, namespaceURI;
rb_scan_args(argc, argv, "21", &prefix, &name, &namespaceURI);
return numeric_rxml_writer_va_strings(self, Qundef, 3, xmlTextWriterStartAttributeNS, prefix, name, namespaceURI);
}
Starts a new CDATA section. Returns false on failure.
static VALUE rxml_writer_start_cdata(VALUE self)
{
return numeric_rxml_writer_void(self, xmlTextWriterStartCDATA);
}
Starts a comment. Returns false on failure. Note: libxml2 >= 2.6.7 required
static VALUE rxml_writer_start_comment(VALUE self)
{
return numeric_rxml_writer_void(self, xmlTextWriterStartComment);
}
Starts a new document. Returns false on failure.
You may provide an optional hash table to control XML header that will be generated. Valid options are:
-
encoding: the output document encoding, defaults to nil (= UTF-8). Valid
values are the encoding constants defined on XML::Encoding
-
standalone: nil (default) or a boolean to indicate if the document is
standalone or not
static VALUE rxml_writer_start_document(int argc, VALUE* argv, VALUE self)
{
int ret;
VALUE options = Qnil;
rxml_writer_object* rwo;
const xmlChar* xencoding = NULL;
const char* xstandalone = NULL;
rb_scan_args(argc, argv, "01", &options);
if (!NIL_P(options))
{
VALUE encoding, standalone;
encoding = standalone = Qnil;
Check_Type(options, T_HASH);
encoding = rb_hash_aref(options, sEncoding);
xencoding = NIL_P(encoding) ? NULL : (const xmlChar*)xmlGetCharEncodingName(NUM2INT(encoding));
standalone = rb_hash_aref(options, sStandalone);
if (NIL_P(standalone))
{
xstandalone = NULL;
}
else
{
xstandalone = RTEST(standalone) ? "yes" : "no";
}
}
rwo = rxml_textwriter_get(self);
rwo->encoding = rxml_figure_encoding(xencoding);
ret = xmlTextWriterStartDocument(rwo->writer, NULL, (const char*)xencoding, xstandalone);
return (-1 == ret ? Qfalse : Qtrue);
}
Starts a DTD. Returns false on failure.
static VALUE rxml_writer_start_dtd(int argc, VALUE* argv, VALUE self)
{
VALUE name, pubid, sysid;
rb_scan_args(argc, argv, "12", &name, &pubid, &sysid);
return numeric_rxml_writer_va_strings(self, Qundef, 3, xmlTextWriterStartDTD, name, pubid, sysid);
}
Starts a DTD attribute list (<!ATTLIST … >). Returns false on failure.
static VALUE rxml_writer_start_dtd_attlist(VALUE self, VALUE name)
{
return numeric_rxml_writer_string(self, name, xmlTextWriterStartDTDAttlist);
}
Starts a DTD element (<!ELEMENT … >). Returns false on failure.
static VALUE rxml_writer_start_dtd_element(VALUE self, VALUE name)
{
return numeric_rxml_writer_string(self, name, xmlTextWriterStartDTDElement);
}
Starts a DTD entity (<!ENTITY … >). Returns false on failure.
static VALUE rxml_writer_start_dtd_entity(int argc, VALUE* argv, VALUE self)
{
VALUE name, pe;
rb_scan_args(argc, argv, "11", &name, &pe);
if (NIL_P(pe))
{
pe = Qfalse;
}
return numeric_rxml_writer_va_strings(self, pe, 1, xmlTextWriterStartDTDEntity, name);
}
Starts a new element. Returns false on failure.
static VALUE rxml_writer_start_element(VALUE self, VALUE name)
{
return numeric_rxml_writer_string(self, name, xmlTextWriterStartElement);
}
Starts a new namespaced element. Returns false on failure.
Note: by default, the xmlns: definition is repeated on every element. If you want the prefix, but don’t want the xmlns: declaration repeated, set namespaceURI to nil or omit it. Don’t forget to declare the namespace prefix somewhere earlier.
static VALUE rxml_writer_start_element_ns(int argc, VALUE* argv, VALUE self)
{
VALUE prefix, name, namespaceURI;
rb_scan_args(argc, argv, "21", &prefix, &name, &namespaceURI);
return numeric_rxml_writer_va_strings(self, Qundef, 3, xmlTextWriterStartElementNS, prefix, name, namespaceURI);
}
Starts a new processing instruction. Returns false on failure.
static VALUE rxml_writer_start_pi(VALUE self, VALUE target)
{
return numeric_rxml_writer_string(self, target, xmlTextWriterStartPI);
}
Writes a full attribute, all at once. Returns false on failure. Same as start_attribute(name) + write_string(content) + end_attribute.
static VALUE rxml_writer_write_attribute(VALUE self, VALUE name, VALUE content)
{
return numeric_rxml_writer_va_strings(self, Qundef, 2, xmlTextWriterWriteAttribute, name, content);
}
Writes a full namespaced attribute, all at once. Returns false on failure. Same as start_attribute_ns(prefix, name, namespaceURI) + write_string(content) + end_attribute.
Notes:
-
by default, the xmlns: definition is repeated on every element. If you want
the prefix, but don’t want the xmlns: declaration repeated, set namespaceURI to nil or omit it. Don’t forget to declare the namespace prefix somewhere earlier.
-
contentcan be omitted too for an empty attribute
static VALUE rxml_writer_write_attribute_ns(int argc, VALUE* argv, VALUE self)
{
VALUE prefix, name, namespaceURI, content;
rb_scan_args(argc, argv, "22", &prefix, &name, &namespaceURI, &content);
return numeric_rxml_writer_va_strings(self, Qundef, 4, xmlTextWriterWriteAttributeNS, prefix, name, namespaceURI, content);
}
Writes a full CDATA section, all at once. Returns false on failure. This is equivalent to start_cdata + write_string(content) + end_cdata.
static VALUE rxml_writer_write_cdata(VALUE self, VALUE content)
{
return numeric_rxml_writer_string(self, content, xmlTextWriterWriteCDATA);
}
Writes a full comment tag, all at once. Returns false on failure. This is equivalent to start_comment + write_string(content) + end_comment.
static VALUE rxml_writer_write_comment(VALUE self, VALUE content)
{
return numeric_rxml_writer_string(self, content, xmlTextWriterWriteComment);
}
Writes a DTD, all at once. Returns false on failure.
-
name: dtd name
-
publicId: external subset public identifier, use nil for a SYSTEM doctype
-
systemId: external subset system identifier
-
subset: content
Examples:
writer.write_dtd 'html' #=> <!DOCTYPE html> writer.write_dtd 'docbook', nil, 'http://www.docbook.org/xml/5.0/dtd/docbook.dtd' #=> <!DOCTYPE docbook SYSTEM "http://www.docbook.org/xml/5.0/dtd/docbook.dtd"> writer.write_dtd 'html', '-//W3C//DTD XHTML 1.1//EN', 'http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd' #=> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> writer.write_dtd 'person', nil, nil, '<!ELEMENT person (firstname,lastname)><!ELEMENT firstname (#PCDATA)><!ELEMENT lastname (#PCDATA)>' #=> <!DOCTYPE person [<!ELEMENT person (firstname,lastname)><!ELEMENT firstname (#PCDATA)><!ELEMENT lastname (#PCDATA)>]>
static VALUE rxml_writer_write_dtd(int argc, VALUE* argv, VALUE self)
{
VALUE name, pubid, sysid, subset;
rb_scan_args(argc, argv, "13", &name, &pubid, &sysid, &subset);
return numeric_rxml_writer_va_strings(self, Qundef, 4, xmlTextWriterWriteDTD, name, pubid, sysid, subset);
}
Writes a DTD attribute list, all at once. Returns false on failure.
writer.write_dtd_attlist 'id', 'ID #IMPLIED' #=> <!ATTLIST id ID #IMPLIED>
static VALUE rxml_writer_write_dtd_attlist(VALUE self, VALUE name, VALUE content)
{
return numeric_rxml_writer_va_strings(self, Qundef, 2, xmlTextWriterWriteDTDAttlist, name, content);
}
Writes a full DTD element, all at once. Returns false on failure.
writer.write_dtd_element 'person', '(firstname,lastname)' #=> <!ELEMENT person (firstname,lastname)>
static VALUE rxml_writer_write_dtd_element(VALUE self, VALUE name, VALUE content)
{
return numeric_rxml_writer_va_strings(self, Qundef, 2, xmlTextWriterWriteDTDElement, name, content);
}
Writes a DTD entity, all at once. Returns false on failure.
static VALUE rxml_writer_write_dtd_entity(VALUE self, VALUE name, VALUE pubid, VALUE sysid, VALUE ndataid, VALUE content, VALUE pe)
{
return numeric_rxml_writer_va_strings(self, pe, 5, xmlTextWriterWriteDTDEntity, name, pubid, sysid, ndataid, content);
}
Writes a DTD external entity. The entity must have been started with start_dtd_entity. Returns false on failure.
-
name: the name of the DTD entity
-
publicId: the public identifier, which is an alternative to the system identifier
-
systemId: the system identifier, which is the URI of the DTD
-
ndataid: the xml notation name
-
pe:
trueif this is a parameter entity (to be used only in the DTD
itself), false if not
static VALUE rxml_writer_write_dtd_external_entity(VALUE self, VALUE name, VALUE pubid, VALUE sysid, VALUE ndataid, VALUE pe)
{
return numeric_rxml_writer_va_strings(self, pe, 4, xmlTextWriterWriteDTDExternalEntity, name, pubid, sysid, ndataid);
}
Writes the contents of a DTD external entity, all at once. Returns false on failure.
static VALUE rxml_writer_write_dtd_external_entity_contents(VALUE self, VALUE pubid, VALUE sysid, VALUE ndataid)
{
return numeric_rxml_writer_va_strings(self, Qundef, 3, xmlTextWriterWriteDTDExternalEntityContents, pubid, sysid, ndataid);
}
Writes a DTD internal entity, all at once. Returns false on failure.
Examples:
writer.write_dtd_entity 'Shape', '(rect|circle|poly|default)', true #=> <!ENTITY % Shape "(rect|circle|poly|default)"> writer.write_dtd_entity 'delta', 'δ', false #=> <!ENTITY delta "δ">
static VALUE rxml_writer_write_dtd_internal_entity(VALUE self, VALUE name, VALUE content, VALUE pe)
{
return numeric_rxml_writer_va_strings(self, pe, 2, xmlTextWriterWriteDTDInternalEntity, name, content);
}
Writes a DTD entity, all at once. Returns false on failure.
static VALUE rxml_writer_write_dtd_notation(VALUE self, VALUE name, VALUE pubid, VALUE sysid)
{
return numeric_rxml_writer_va_strings(self, Qundef, 3, xmlTextWriterWriteDTDNotation, name, pubid, sysid);
}
Writes a full element tag, all at once. Returns false on failure. This is equivalent to start_element(name) + write_string(content) + end_element.
static VALUE rxml_writer_write_element(int argc, VALUE* argv, VALUE self)
{
VALUE name, content;
rb_scan_args(argc, argv, "11", &name, &content);
if (Qnil == content)
{
if (Qfalse == rxml_writer_start_element(self, name))
{
return Qfalse;
}
return rxml_writer_end_element(self);
}
else
{
return numeric_rxml_writer_va_strings(self, Qundef, 2, xmlTextWriterWriteElement, name, content);
}
}
Writes a full namespaced element tag, all at once. Returns false on failure. This is a shortcut for start_element_ns(prefix, name, namespaceURI) + write_string(content) + end_element.
Notes:
-
by default, the xmlns: definition is repeated on every element. If you want
the prefix, but don’t want the xmlns: declaration repeated, set namespaceURI to nil or omit it. Don’t forget to declare the namespace prefix somewhere earlier.
-
contentcan be omitted for an empty tag
static VALUE rxml_writer_write_element_ns(int argc, VALUE* argv, VALUE self)
{
VALUE prefix, name, namespaceURI, content;
rb_scan_args(argc, argv, "22", &prefix, &name, &namespaceURI, &content);
if (Qnil == content)
{
VALUE argv[3] = { prefix, name, namespaceURI };
if (Qfalse == rxml_writer_start_element_ns(ARRAY_SIZE(argv), argv, self))
{
return Qfalse;
}
return rxml_writer_end_element(self);
}
else
{
return numeric_rxml_writer_va_strings(self, Qundef, 4, xmlTextWriterWriteElementNS, prefix, name, namespaceURI, content);
}
}
Writes a full CDATA tag, all at once. Returns false on failure. This is a shortcut for start_pi(target) + write_string(content) + end_pi.
static VALUE rxml_writer_write_pi(VALUE self, VALUE target, VALUE content)
{
return numeric_rxml_writer_va_strings(self, Qundef, 2, xmlTextWriterWritePI, target, content);
}
Writes the string content as is, reserved characters are not translated to their associated entities. Returns false on failure. Consider write_string to handle them.
static VALUE rxml_writer_write_raw(VALUE self, VALUE content)
{
return numeric_rxml_writer_string(self, content, xmlTextWriterWriteRaw);
}
Safely (problematic characters are internally translated to their associated named entities) writes a string into the current node (attribute, element, comment, …). Returns false on failure.
static VALUE rxml_writer_write_string(VALUE self, VALUE content)
{
return numeric_rxml_writer_string(self, content, xmlTextWriterWriteString);
}