Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add XML.build and XML::Writer #3806

Merged
merged 1 commit into from Dec 31, 2016
Merged

Add XML.build and XML::Writer #3806

merged 1 commit into from Dec 31, 2016

Conversation

asterite
Copy link
Member

Right now it's impossible to generate correct XML in an easy way. This PR fixes that. It wraps a libxml2 writer. Writing to the writer directly writes to the underlying IO.

Example:

require "xml"

string = XML.write(indent: "  ") do |xml|
  xml.element("person", id: 1) do
    xml.element("firstname") { xml.text "Jane" }
    xml.element("lastname") { xml.text "Doe" }
  end
end

puts string

Output:

<?xml version="1.0"?>
<person id="1">
  <firstname>Jane</firstname>
  <lastname>Doe</lastname>
</person>

As you can see, there's no "magic" in the writer. You have to call element to emit elements. You also have attribute, text and other methods to emit these individually.

I thought about either adding a separate XML::Builder class that uses method_missing and is similar to Nokogiri::XML::Builder, or either adding that functionality to XML::Writer, but I'm not sure about that. For example in Nokogiri you have to use type_ or object_id_ (with an ending underscore) if you need these names so they don't conflict with existing methods. Also you basically have to learn a new mini-language for emitting stuff, and it gets a bit more complex when namespaces and attributes are involved. So I prefer to keep things simple and straight-forward here (though a builder using method_missing is definitely possible (in master)).

call SetQuoteChar, char.ord
end

# TODO: mark as private
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With #3747 merged and part of 0.20.3, cannot this macro be marked as private already?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Last thing I knew, the binaries that travis uses for linux weren't up to date. I'll try to change this and see if it's already fixed :-)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It failed... jhass used to maintain these, I guess we should take that over

@ysbaddaden
Copy link
Contributor

Pedantic: I'm not sure about the XML.write that returns a String; it sounds like it writes to a file. What about XML.build to reflect on String.build?

Copy link
Contributor

@ysbaddaden ysbaddaden left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I noted some typos. Code looks good, and feature is 👍

end

# Emits the start attribute of an attribute with namespace info.
def start_attribute(prefix : String?, name : String, namesapce_uri : String?)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo: namespace_uri

end_element
end

# Emits the start attribute of an attribute.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The "start attribute of an attribute"? Did you mean the "start of an attribute"? Same below.

end

# Emits the start of the document, invokes the block,
# and the emits the end of the document.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"then emits"

@@ -0,0 +1,312 @@
module XML
# Returns the resulting of writing XML to the yielded `XML::Writer`.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"returns the resulting String"?

end

# Emits the start of a comment, invokes the block
# and the emits the end of the comment.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"then emits"

end

# Emits the start of a CDATA section, invokes the block
# and then emits the enf of the CDATA section.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"emits the end" or maybe "closes the CDATA section"? Same for other occurrences.


# Emits text content.
#
# Text content can happen inside of an element, attribute value, cdata, dtd, etc.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe have backtics and hash to link to mentioned method?

@asterite asterite changed the title Add XML.write and XML::Writer Add XML.build and XML::Writer Dec 31, 2016
@asterite asterite added this to the 0.20.4 milestone Dec 31, 2016
@asterite asterite merged commit 3582156 into master Dec 31, 2016
@asterite asterite deleted the feature/xml_writer branch December 31, 2016 13:30
@splattael
Copy link
Contributor

Shouldn't the class XML::Writer be called XML::Builder similar to String::Builder?

@luislavena
Copy link
Contributor

@splattael we could make that extensive to JSON::Builder, CSV::Builder, HTML::Builder (now separate project).

@asterite, since this was already merged, think will accept a PR with that rename? 😄

@asterite
Copy link
Member Author

Sounds good. Also YAML. I wasn't sure because it doesn't build xml nodes, it writes an xml string to an IO, but I don't think we'll have a separate builder for something else, so having consistent names is good.

@asterite
Copy link
Member Author

asterite commented Jan 1, 2017

@luislavena Don't worry, I already started this refactor. I decided to do it myself because there's no JSON::Builder right now and I'm thinking of making to_json accept a builder, so it's similar to to_yaml, and you can configure its indent, etc.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants