Skip to content

Commit

Permalink
allow setting and deleting of attributes on supported XML::Node types
Browse files Browse the repository at this point in the history
  • Loading branch information
bmmcginty committed Jan 23, 2017
1 parent 15032cc commit c8a96b7
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 0 deletions.
44 changes: 44 additions & 0 deletions spec/std/xml/xml_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,50 @@ describe XML do
person["id"].should eq("1")
end

it "sets node attributes" do
doc = XML.parse(<<-XML
<?xml version='1.0' encoding='UTF-8'?>
<person id="1">
<name>John</name>
</person>
XML
)
person = doc.root.not_nil!
person.name.should eq("person")
person["id"].should eq "1"
person["id"] = "one"
person["id"].should eq "one"
person["id2"]?.should eq nil
person["id2"] = "two"
person["id2"].should eq "two"
person_s = person.to_s
person_s.index("id=\"one\"").should_not eq nil
person_s.index("id2=\"two\"").should_not eq nil
end

it "deletes node attributes" do
doc = XML.parse(<<-XML
<?xml version='1.0' encoding='UTF-8'?>
<person id="1">
<name>John</name>
</person>
XML
)
person = doc.root.not_nil!
person.name.should eq("person")
person["id"].should eq "1"
person.delete("id")
person["id"]?.should eq nil
person["id2"] = "2"
deleted_attribute = person.delete("id2")
deleted_attribute.should eq "2"
deleted_attribute = person.delete("id2")
deleted_attribute.should eq nil
person_s = person.to_s
person_s.index("id=").should eq nil
person_s.index("id2=").should eq nil
end

it "raises exception on empty string" do
expect_raises XML::Error, "Document is empty" do
XML.parse("")
Expand Down
17 changes: 17 additions & 0 deletions src/xml/attributes.cr
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,23 @@ struct XML::Attributes
find { |node| node.name == name }
end

def delete(name : String)
curr = LibXML.xmlHasProp(@node, name)
return nil if curr.null?
content = Node.new(curr).content
LibXML.xmlRemoveProp(curr)
content
end

def []=(name : String, value : String)
curr = self[name]?
if curr
curr.content = value
else
LibXML.xmlNewProp(@node, name, value)
end
end

def each : Nil
return unless @node.element?

Expand Down
4 changes: 4 additions & 0 deletions src/xml/libxml2.cr
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,10 @@ lib LibXML
fun xmlXPathNodeSetCreate(node : Node*) : NodeSet*
fun xmlXPathNodeSetAddUnique(cur : NodeSet*, val : Node*) : Int
fun xmlNodeGetContent(node : Node*) : UInt8*

fun xmlNewProp(node : Node*, name : UInt8*, value : UInt8*) : Attr*
fun xmlHasProp(node : Node*, name : UInt8*) : Attr*
fun xmlRemoveProp(cur : Attr*) : Int
fun xmlNodeSetContent(node : Node*, content : UInt8*)
fun xmlNodeSetName(node : Node*, name : UInt8*)

Expand Down
12 changes: 12 additions & 0 deletions src/xml/node.cr
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,18 @@ struct XML::Node
attributes[attribute].content || raise(KeyError.new("Missing attribute: #{attribute}"))
end

# sets *attribute* of this node to *value*. Raises `XML::Error` if this node does not support attributes.
def []=(name : String, value : String)
raise XML::Error.new("Can't set attribute of #{type}", 0) unless element?
attributes[name] = value
end

# Deletes attribute given by *name*.
# Returns attributes value, or `nil` if attribute not found.
def delete(name : String)
attributes.delete(name)
end

# Gets the attribute content for the *attribute* given by name. Returns `nil` if attribute is not found.
def []?(attribute : String) : String?
attributes[attribute]?.try &.content
Expand Down

0 comments on commit c8a96b7

Please sign in to comment.