0

I am trying to change the data in the below XML file. I am sure about one thing that the data will be in <string> tag but inside that it can be nested to any extent. So to do that I have come up with a recursive solution which seems like the right code but is not doing any change.

Recursion in C or C++ is easy as in that change is easily reflected in the actual parameter but in Ruby I am not able to figure out how to reflect that.

Source XML:

<document>
  <string id="title">Continue without CableCARD?</string>
  <string id="bodytext"/>
  <string id = "f" >This is data1
    <p>
      <t>
        this is data2
      </t>
    </p>
    this is data3
  </string>
</document>

Ruby code:

require 'nokogiri'

doc = Nokogiri::XML(File.open("d.xml"))
def rec_func(s)
  if s.child.class == NilClass
    return s
  end
  array = s.children()
  array.each do |element|
    if element == Nokogiri::XML::Text
      s.content = s.content + "A"
    else
      element =  rec_func(element)
      puts "##########"
      puts element
    end
  end
  s.children = array # I added this statement as I was in doubt whether the changes in this array will be reflected in the parent s or not.

  return s
end
doc.xpath("//string").each do |node|
  k = rec_func node
  puts "$$$$$$$$$$$$$$"
end

Please someone suggest any change in the code to make it work.

the Tin Man
  • 158,662
  • 42
  • 215
  • 303
Learner
  • 59
  • 8
  • First at all, the condition `element == Nokogiri::XML::Text` doesn't work. `element` is not equal to its class... You probably want to do it like this: `Nokogiri::XML::Text === element`. – Grych Aug 01 '14 at 08:03
  • Its not working then also – Learner Aug 01 '14 at 08:39

1 Answers1

0

Here you are. I parse each children of "//string" with recursive method parse_children. In this method I iterate through all the children and for a specific child I check if it is XML::Text. If yes, this ends the recursion (and do something with this text). If not, recursive call parse_children with the children of this element.

def parse_children(children)
  children.each do |child|
    case child
    when Nokogiri::XML::Text
      child.content = child.content.strip + "A"
    when Nokogiri::XML::Element
      parse_children child.children
    end
  end
end

doc = Nokogiri::XML.parse(xml)
doc.xpath('//string').each do |s|
  parse_children s.children
end

puts doc.to_xml
Grych
  • 2,861
  • 13
  • 22
  • It is not working appropriately but i modified it to get the work done!! Thanks man!! The changes in the doc is not reflected in the actual xml file .. can you please let me know the way to get the change get reflected in the xml file. – Learner Aug 01 '14 at 10:51
  • I don't know what do you mean with *working appropriately*, but my code does the trick: adding letter "A" at the end of each `XML::Text`. – Grych Aug 01 '14 at 10:57
  • Ya I agree but the code also added a "A" between

    and tag which was not needed. But the main problem is that the change is not reflected in the source xml file

    – Learner Aug 01 '14 at 11:07
  • I am having a little problem..Like above I am recursively traversing the xml file in a code and Whem I am rewriting the data the the document is losing indentation.. Is this an issue with nokogiri and how this can be resolved .. I mean how to maintain indentation when we traverse an xml doc recursively – Learner Aug 07 '14 at 09:53
  • Here http://stackoverflow.com/questions/1898829/how-do-i-pretty-print-html-with-nokogiri is the answer for the formatting issue – Grych Aug 07 '14 at 09:58