Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 26 additions & 8 deletions src/xml.cr
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,34 @@ require "./xml/libxml2"
# string # => "<?xml version=\"1.0\"?>\n<person id=\"1\">\n <firstname>Jane</firstname>\n <lastname>Doe</lastname>\n</person>\n"
# ```
module XML
# Wraps a block that uses a XML parser context. Allocates the
# context and ensures the context is freed after use.
private def self.parse_xml(&)
ctxt = LibXML.xmlNewParserCtxt
begin
from_ptr(ctxt) { yield ctxt }
ensure
LibXML.xmlFreeParserCtxt(ctxt)
end
end

# Wraps a block that uses a HTML parser context. Allocates the
# context and ensures the context is freed after use.
private def self.parse_html(&)
ctxt = LibXML.htmlNewParserCtxt
begin
from_ptr(ctxt) { yield ctxt }
ensure
LibXML.htmlFreeParserCtxt(ctxt)
end
end

# Parses an XML document from *string* with *options* into an `XML::Node`.
#
# See `ParserOptions.default` for default options.
def self.parse(string : String, options : ParserOptions = ParserOptions.default) : Document
raise XML::Error.new("Document is empty", 0) if string.empty?
ctxt = LibXML.xmlNewParserCtxt
from_ptr(ctxt) do
parse_xml do |ctxt|
LibXML.xmlCtxtReadMemory(ctxt, string, string.bytesize, nil, nil, options)
end
end
Expand All @@ -66,8 +87,7 @@ module XML
#
# See `ParserOptions.default` for default options.
def self.parse(io : IO, options : ParserOptions = ParserOptions.default) : Document
ctxt = LibXML.xmlNewParserCtxt
from_ptr(ctxt) do
parse_xml do |ctxt|
LibXML.xmlCtxtReadIO(ctxt, ->read_callback, ->close_callback, Box(IO).box(io), nil, nil, options)
end
end
Expand All @@ -77,8 +97,7 @@ module XML
# See `HTMLParserOptions.default` for default options.
def self.parse_html(string : String, options : HTMLParserOptions = HTMLParserOptions.default) : Document
raise XML::Error.new("Document is empty", 0) if string.empty?
ctxt = LibXML.htmlNewParserCtxt
from_ptr(ctxt) do
parse_html do |ctxt|
LibXML.htmlCtxtReadMemory(ctxt, string, string.bytesize, nil, "utf-8", options)
end
end
Expand All @@ -87,8 +106,7 @@ module XML
#
# See `HTMLParserOptions.default` for default options.
def self.parse_html(io : IO, options : HTMLParserOptions = HTMLParserOptions.default) : Document
ctxt = LibXML.htmlNewParserCtxt
from_ptr(ctxt) do
parse_html do |ctxt|
LibXML.htmlCtxtReadIO(ctxt, ->read_callback, ->close_callback, Box(IO).box(io), nil, "utf-8", options)
end
end
Expand Down
2 changes: 2 additions & 0 deletions src/xml/libxml2.cr
Original file line number Diff line number Diff line change
Expand Up @@ -175,10 +175,12 @@ lib LibXML
fun xmlNewParserCtxt : ParserCtxt
fun xmlCtxtReadIO(ParserCtxt, ioread : InputReadCallback, ioclose : InputCloseCallback, ioctx : Void*, url : UInt8*, encoding : UInt8*, options : XML::ParserOptions) : Doc*
fun xmlCtxtReadMemory(ParserCtxt, buffer : UInt8*, size : Int, url : UInt8*, encoding : UInt8*, options : XML::ParserOptions) : Doc*
fun xmlFreeParserCtxt(ctxt : ParserCtxt)

fun htmlNewParserCtxt : HTMLParserCtxt
fun htmlCtxtReadMemory(HTMLParserCtxt, buffer : UInt8*, size : Int, url : UInt8*, encoding : UInt8*, options : XML::HTMLParserOptions) : Doc*
fun htmlCtxtReadIO(HTMLParserCtxt, ioread : InputReadCallback, ioclose : InputCloseCallback, ioctx : Void*, url : UInt8*, encoding : UInt8*, options : XML::HTMLParserOptions) : Doc*
fun htmlFreeParserCtxt(ctxt : HTMLParserCtxt)

fun xmlDocGetRootElement(doc : Doc*) : Node*
fun xmlXPathNodeSetCreate(node : Node*) : NodeSet*
Expand Down