Class: XMLCodec::XMLElement
- Inherits:
-
Object
- Object
- XMLCodec::XMLElement
- Defined in:
- lib/element.rb
Overview
This class should be inherited from to create classes that are able to import and export XML elements and their children. It provides three main functions: xmlattr, xmlsubel and xmlsubel_mult.
To create an importer/exporter for a XML format all that’s needed is to create a class for each of the elements and then declare their atributes and subelements.
Two other functions have an important role. elname declares the name of the XML element the class represents. elwithvalue declares that the element has no subelements and includes only text content.
After the class is defined import_xml can be used to import the content from a Nokogiri Element or Document and create_xml can be used to create the XML DOM of the element as a child to a Nokogiri Element or Document. For big documents these are usually too slow and memory hungry, using xml_text to export to XML and import_xml_text to import XML are probably better ideas. import_xml_text is just a utility function around XMLStreamObjectParser, that allow more flexible stream parsing of XML files while still using the same XMLElement objects.
Constant Summary collapse
- INDENT_STR =
' '
- CACHE =
{}
Instance Attribute Summary collapse
-
#__parent ⇒ Object
Returns the value of attribute __parent.
-
#__xml_text ⇒ Object
Returns the value of attribute __xml_text.
-
#element_id ⇒ Object
Returns the value of attribute element_id.
-
#parent_id ⇒ Object
Returns the value of attribute parent_id.
Class Method Summary collapse
-
._import_xml_dom(xmlel) ⇒ Object
Import the XML into an object from a Nokogiri XML Node or Document.
-
._import_xml_text(text) ⇒ Object
Import the XML directly from the text.
-
.get_element_class(name) ⇒ Object
Gets the class for a certain element name.
-
.get_element_names(name) ⇒ Object
Gets the possible element names for a certain element.
-
.import_xml(obj) ⇒ Object
Import the XML into an object from a Nokogiri XML Node or Document or from a string.
-
.new_with_content(attrs, children) ⇒ Object
Create a new element passing it all the atributes, children and texts.
Instance Method Summary collapse
-
#add_attr(attrs) ⇒ Object
add the attributes passed as a hash to the element.
-
#add_subel(children) ⇒ Object
add the subelements into the element.
-
#add_subelements(all_children) ⇒ Object
If the class is one with many subelements import all of them into the object.
-
#add_texts(texts) ⇒ Object
add the text elements into the element.
-
#already_partial_export_ended? ⇒ Boolean
Have we already ended the partial export of this element?.
-
#already_partial_exported? ⇒ Boolean
Have we already started the partial export of this element?.
-
#create_xml(parent) ⇒ Object
Creates the xml for the element inside the parent element.
-
#delete_element(element) ⇒ Object
Remove the given subelement from the element.
-
#end_partial_export(file) ⇒ Object
Ends the partial exporting of the element.
-
#has_subelements? ⇒ Boolean
Method that checks if a given class has subelements.
-
#hasvalue? ⇒ Boolean
tests if the element is a value element as defined by ‘elwithvalue’.
-
#partial_export(file) ⇒ Object
Export this element into a file.
-
#start_partial_export(file) ⇒ Object
Starts to export the element to a file.
-
#xml_text ⇒ Object
create the XML text of the element.
Instance Attribute Details
#__parent ⇒ Object
Returns the value of attribute __parent.
33 34 35 |
# File 'lib/element.rb', line 33 def __parent @__parent end |
#__xml_text ⇒ Object
Returns the value of attribute __xml_text.
32 33 34 |
# File 'lib/element.rb', line 32 def __xml_text @__xml_text end |
#element_id ⇒ Object
Returns the value of attribute element_id.
32 33 34 |
# File 'lib/element.rb', line 32 def element_id @element_id end |
#parent_id ⇒ Object
Returns the value of attribute parent_id.
32 33 34 |
# File 'lib/element.rb', line 32 def parent_id @parent_id end |
Class Method Details
._import_xml_dom(xmlel) ⇒ Object
Import the XML into an object from a Nokogiri XML Node or Document. This call is recursive and imports any subelements found into the corresponding objects.
395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 |
# File 'lib/element.rb', line 395 def self._import_xml_dom(xmlel) if xmlel.is_a? Nokogiri::XML::Document xmlel = xmlel.root end elements = [] xmlel.children.each do |e| if e.text? elements << e.text else elclass = get_element_class(e.name) if not elclass if class_variable_get('@@strict_parsing') raise ElementClassNotFound, "No class defined for element type: '#{e.name}'" end else elements << elclass._import_xml_dom(e) end end end attributes = {} xmlel.attributes.each do |name, attr| attributes[name] = attr.value end elclass = get_element_class(xmlel.name) return nil if not elclass elclass.new_with_content(attributes, elements) end |
._import_xml_text(text) ⇒ Object
Import the XML directly from the text.
427 428 429 430 431 |
# File 'lib/element.rb', line 427 def self._import_xml_text(text) parser = XMLStreamObjectParser.new(self) parser.parse(text) parser.top_element end |
.get_element_class(name) ⇒ Object
Gets the class for a certain element name.
338 339 340 341 342 343 344 |
# File 'lib/element.rb', line 338 def self.get_element_class(name) cl = elclasses[name.to_sym] if not cl and class_variable_get('@@strict_parsing') raise ElementClassNotFound, "No class defined for element type: '" + name.to_s + "'" end cl end |
.get_element_names(name) ⇒ Object
Gets the possible element names for a certain element.
347 348 349 |
# File 'lib/element.rb', line 347 def self.get_element_names(name) get_element_class(name).get_elnames end |
.import_xml(obj) ⇒ Object
Import the XML into an object from a Nokogiri XML Node or Document or from a string.
381 382 383 384 385 386 387 388 389 390 |
# File 'lib/element.rb', line 381 def self.import_xml(obj) if obj.instance_of? String _import_xml_text(obj) elsif obj.instance_of? Nokogiri::XML::Node or obj.instance_of? Nokogiri::XML::Document _import_xml_dom(obj) else nil end end |
.new_with_content(attrs, children) ⇒ Object
Create a new element passing it all the atributes, children and texts
434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 |
# File 'lib/element.rb', line 434 def self.new_with_content(attrs, children) text_children = [] element_children = [] children.each do |c| if c.is_a? String text_children << c else element_children << c end end obj = self.allocate obj.add_attr(attrs) obj.add_subel(element_children) obj.add_texts(text_children) if obj.has_subelements? obj.add_subelements(children) end obj end |
Instance Method Details
#add_attr(attrs) ⇒ Object
add the attributes passed as a hash to the element
457 458 459 460 461 462 463 464 465 466 467 |
# File 'lib/element.rb', line 457 def add_attr(attrs) attrs.each do |name, value| if not self.class.attr_names.include?(name.to_sym) if self.class.class_variable_get('@@strict_parsing') raise ElementAttributeNotFound, "No attribute '#{name}' defined for class '#{self.class}'" end else self.send("#{name}=", value) end end end |
#add_subel(children) ⇒ Object
add the subelements into the element
477 478 479 480 481 482 483 484 485 486 487 |
# File 'lib/element.rb', line 477 def add_subel(children) children.each do |c| if subel_name = get_subel(c.class) if self.class.subel_mult? subel_name self.send(subel_name) << c else self.send(subel_name.to_s+'=', c) end end end end |
#add_subelements(all_children) ⇒ Object
If the class is one with many subelements import all of them into the object.
491 492 493 |
# File 'lib/element.rb', line 491 def add_subelements(all_children) all_children.each {|c| self.subelements << c} end |
#add_texts(texts) ⇒ Object
add the text elements into the element
470 471 472 473 474 |
# File 'lib/element.rb', line 470 def add_texts(texts) if hasvalue? @value = texts.join end end |
#already_partial_export_ended? ⇒ Boolean
Have we already ended the partial export of this element?
517 518 519 |
# File 'lib/element.rb', line 517 def already_partial_export_ended? (@already_partial_export_ended ||= false) end |
#already_partial_exported? ⇒ Boolean
Have we already started the partial export of this element?
512 513 514 |
# File 'lib/element.rb', line 512 def already_partial_exported? (@already_partial_exported ||= false) end |
#create_xml(parent) ⇒ Object
Creates the xml for the element inside the parent element. The parent passed should be a Nokogiri XML Node or Document. This call is recursive creating the XML for any subelements.
364 365 366 367 368 369 370 371 372 373 374 375 376 377 |
# File 'lib/element.rb', line 364 def create_xml(parent) xmlel = parent.add_child Nokogiri::XML::Element.new(self.elname.to_s, parent) if self.hasvalue? xmlel.add_child self.value end create_xml_attr(xmlel) create_xml_subel(xmlel) if has_subelements? create_xml_subelements(xmlel) end xmlel end |
#delete_element(element) ⇒ Object
Remove the given subelement from the element
311 312 313 314 315 316 317 318 319 320 321 322 323 324 |
# File 'lib/element.rb', line 311 def delete_element(element) self.class.each_subel do |a| value = self.send(a) if self.class.subel_mult? a value.delete_element(element) else self.send(a.to_s+'=', nil) if value == element end end if has_subelements? @subelements.delete_element(element) end end |
#end_partial_export(file) ⇒ Object
Ends the partial exporting of the element.
553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 |
# File 'lib/element.rb', line 553 def end_partial_export(file) if not already_partial_export_ended? @already_partial_export_ended = true if not already_partial_exported? raise "<#{self} Trying to end the export of an element that hasn't"+ " been started yet" end each_subelement do |e| e.end_partial_export(file) end file << create_close_tag if self.__parent self.__parent.delete_element(self) end end end |
#has_subelements? ⇒ Boolean
Method that checks if a given class has subelements. This is usually only used when exporting stuff.
353 |
# File 'lib/element.rb', line 353 def has_subelements?; false; end |
#hasvalue? ⇒ Boolean
tests if the element is a value element as defined by ‘elwithvalue’
356 357 358 |
# File 'lib/element.rb', line 356 def hasvalue? false end |
#partial_export(file) ⇒ Object
Export this element into a file. Will also start to export the parents of the element. It’s equivalent to calling start_partial_export followed by end_partial_export.
524 525 526 527 528 529 |
# File 'lib/element.rb', line 524 def partial_export(file) if not already_partial_exported? start_partial_export(file) end_partial_export(file) end end |
#start_partial_export(file) ⇒ Object
Starts to export the element to a file. all the existing elements will be exported. After calling this you should only add stuff that you will export explicitly by calling partial_export or start_partial_export.
534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 |
# File 'lib/element.rb', line 534 def start_partial_export(file) if not already_partial_exported? @already_partial_exported = true if self.__parent self.__parent.start_partial_export(file) end file << create_open_tag if self.hasvalue? file << XMLCodec::XMLUtils::escape_xml(self.value) end each_subelement do |e| e.partial_export(file) end end end |
#xml_text ⇒ Object
create the XML text of the element
497 498 499 500 501 502 503 504 505 506 507 508 509 |
# File 'lib/element.rb', line 497 def xml_text str = create_open_tag if self.hasvalue? str << XMLCodec::XMLUtils::escape_xml(self.value) end each_subelement do |e| str << e.xml_text end str << create_close_tag str end |