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 REXML Element or Document and create_xml can be used to create the XML DOM of the element as a child to a REXML 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.
WARNING: This API is still very much a work in progress and very rough in certain places. Changes will surely be made.
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
-
.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(xmlel) ⇒ Object
Import the XML into an object from a REXML element.
-
.import_xml_text(text) ⇒ Object
Import the XML directly from the text.
-
.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.
-
#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
.get_element_class(name) ⇒ Object
Gets the class for a certain element name.
339 340 341 342 343 344 345 |
# File 'lib/element.rb', line 339 def self.get_element_class(name) cl = elclasses[name.to_sym] if not cl 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.
348 349 350 |
# File 'lib/element.rb', line 348 def self.get_element_names(name) get_element_class(name).get_elnames end |
.import_xml(xmlel) ⇒ Object
Import the XML into an object from a REXML element. This call is recursive and imports any subelements found into the corresponding objects.
382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 |
# File 'lib/element.rb', line 382 def self.import_xml(xmlel) if xmlel.is_a? REXML::Document xmlel = xmlel.root end elements = [] xmlel.to_a.each do |e| if e.is_a? REXML::Text elements << e.value else elclass = get_element_class(e.name) elements << elclass.import_xml(e) end end attributes = {} xmlel.attributes.each do |name, value| attributes[name] = value end new_with_content(attributes, elements) end |
.import_xml_text(text) ⇒ Object
Import the XML directly from the text. This call receives the text and the classes that should be used to import the subelements.
407 408 409 410 411 |
# File 'lib/element.rb', line 407 def self.import_xml_text(text) parser = XMLStreamObjectParser.new(self) parser.parse(text) parser.top_element end |
.new_with_content(attrs, children) ⇒ Object
Create a new element passing it all the atributes, children and texts
414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 |
# File 'lib/element.rb', line 414 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
437 438 439 440 441 |
# File 'lib/element.rb', line 437 def add_attr(attrs) attrs.each do |name, value| self.send("#{name}=", value) end end |
#add_subel(children) ⇒ Object
add the subelements into the element
451 452 453 454 455 456 457 458 459 460 461 |
# File 'lib/element.rb', line 451 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.
465 466 467 |
# File 'lib/element.rb', line 465 def add_subelements(all_children) all_children.each {|c| self.subelements << c} end |
#add_texts(texts) ⇒ Object
add the text elements into the element
444 445 446 447 448 |
# File 'lib/element.rb', line 444 def add_texts(texts) if hasvalue? @value = texts.join end end |
#create_xml(parent) ⇒ Object
Creates the xml for the element inside the parent element. The parent passed should be a REXML element or document. This call is recursive creating the XML for any subelements.
365 366 367 368 369 370 371 372 373 374 375 376 377 378 |
# File 'lib/element.rb', line 365 def create_xml(parent) xmlel = parent.add_element self.elname.to_s if self.hasvalue? xmlel.text = 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
312 313 314 315 316 317 318 319 320 321 322 323 324 325 |
# File 'lib/element.rb', line 312 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.
518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 |
# File 'lib/element.rb', line 518 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.
354 |
# File 'lib/element.rb', line 354 def has_subelements?; false; end |
#hasvalue? ⇒ Boolean
tests if the element is a value element as defined by ‘elwithvalue’
357 358 359 |
# File 'lib/element.rb', line 357 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.
489 490 491 492 493 494 |
# File 'lib/element.rb', line 489 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.
499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 |
# File 'lib/element.rb', line 499 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 << 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. This does not use REXML so should be pretty fast.
472 473 474 475 476 477 478 479 480 481 482 483 484 |
# File 'lib/element.rb', line 472 def xml_text str = create_open_tag if self.hasvalue? str << XMLUtils::escape_xml(self.value) end each_subelement do |e| str << e.xml_text end str << create_close_tag str end |