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.
-
.allvalue? ⇒ Boolean
tests if the element is a value element as defined by ‘elallvalue’.
-
.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.
-
.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’.
-
.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.
- #allvalue? ⇒ Boolean
-
#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
- #hasvalue? ⇒ Boolean
-
#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.
412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 |
# File 'lib/element.rb', line 412 def self._import_xml_dom(xmlel) if xmlel.is_a? Nokogiri::XML::Document xmlel = xmlel.root end elclass = get_element_class(xmlel.name) if not elclass if class_variable_get(:@@strict_parsing) raise ElementClassNotFound, "No class defined for element type: '#{e.name}'" else return nil end end if elclass.allvalue? elements = [xmlel.children.map{|c| c.to_xml(:save_with=>0)}.join] else elements = [] xmlel.children.each do |e| if e.text? elements << e.text else element = _import_xml_dom(e) elements << element if element end end end attributes = {} xmlel.attributes.each do |name, attr| attributes[name] = attr.value end elclass.new_with_content(attributes, elements) end |
._import_xml_text(text) ⇒ Object
Import the XML directly from the text.
449 450 451 452 453 |
# File 'lib/element.rb', line 449 def self._import_xml_text(text) parser = XMLStreamObjectParser.new(self) parser.parse(text) parser.top_element end |
.allvalue? ⇒ Boolean
tests if the element is a value element as defined by ‘elallvalue’
375 |
# File 'lib/element.rb', line 375 def self.allvalue?; false end |
.get_element_class(name) ⇒ Object
Gets the class for a certain element name.
352 353 354 355 356 357 358 |
# File 'lib/element.rb', line 352 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.
361 362 363 |
# File 'lib/element.rb', line 361 def self.get_element_names(name) get_element_class(name).get_elnames end |
.has_subelements? ⇒ Boolean
Method that checks if a given class has subelements. This is usually only used when exporting stuff.
367 |
# File 'lib/element.rb', line 367 def self.has_subelements?; false end |
.hasvalue? ⇒ Boolean
tests if the element is a value element as defined by ‘elwithvalue’
371 |
# File 'lib/element.rb', line 371 def self.hasvalue?; false end |
.import_xml(obj) ⇒ Object
Import the XML into an object from a Nokogiri XML Node or Document or from a string.
398 399 400 401 402 403 404 405 406 407 |
# File 'lib/element.rb', line 398 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
456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 |
# File 'lib/element.rb', line 456 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
479 480 481 482 483 484 485 486 487 488 489 |
# File 'lib/element.rb', line 479 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
499 500 501 502 503 504 505 506 507 508 509 |
# File 'lib/element.rb', line 499 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.
513 514 515 |
# File 'lib/element.rb', line 513 def add_subelements(all_children) all_children.each {|c| self.subelements << c} end |
#add_texts(texts) ⇒ Object
add the text elements into the element
492 493 494 495 496 |
# File 'lib/element.rb', line 492 def add_texts(texts) if self.hasvalue? @value = texts.join end end |
#allvalue? ⇒ Boolean
376 |
# File 'lib/element.rb', line 376 def allvalue?; self.class.allvalue?; end |
#already_partial_export_ended? ⇒ Boolean
Have we already ended the partial export of this element?
539 540 541 |
# File 'lib/element.rb', line 539 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?
534 535 536 |
# File 'lib/element.rb', line 534 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.
381 382 383 384 385 386 387 388 389 390 391 392 393 394 |
# File 'lib/element.rb', line 381 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 self.has_subelements? create_xml_subelements(xmlel) end xmlel end |
#delete_element(element) ⇒ Object
Remove the given subelement from the element
325 326 327 328 329 330 331 332 333 334 335 336 337 338 |
# File 'lib/element.rb', line 325 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.
575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 |
# File 'lib/element.rb', line 575 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
368 |
# File 'lib/element.rb', line 368 def has_subelements?; self.class.has_subelements? end |
#hasvalue? ⇒ Boolean
372 |
# File 'lib/element.rb', line 372 def hasvalue?; self.class.hasvalue? 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.
546 547 548 549 550 551 |
# File 'lib/element.rb', line 546 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.
556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 |
# File 'lib/element.rb', line 556 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
519 520 521 522 523 524 525 526 527 528 529 530 531 |
# File 'lib/element.rb', line 519 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 |