Sunny
Sunny

Reputation: 478

How to replace tag with some value in XML using Nokogiri

I have a predefine XML template with some tags that need to be replaced. The tag values come dynamically from the front-end.

<?xml version="1.0"?>
<catalog>
   <book id="bk101">
      <author>AUTHOR1</author>
      <title>TITLE1</title>
      <genre>Computer</genre>
      <price>44.95</price>
      <publish_date>2000-10-01</publish_date>
      <description>An in-depth look at creating applications 
      with XML.</description>
   </book>
   <book id="bk102">
      <author>AUTHOR2</author>
      <title>TITLE2</title>
      <genre>Fantasy</genre>
      <price>5.95</price>
      <publish_date>2000-12-16</publish_date>
      <description>A former architect battles corporate zombies, 
      an evil sorceress, and her own childhood to become queen 
      of the world.</description>
   </book>
 </catalog>

In above example I need to replace TITLE1, TITLE2, AUTHOR1, AUTHOR2 with the actual value dynamically.

What is the best way to do this? I am using Nokogiri in some Ruby code but have had no luck.

Upvotes: 0

Views: 667

Answers (1)

the Tin Man
the Tin Man

Reputation: 160551

The basic idea is you need to search the XML for the <book> tags. For each book found, retrieve the block of values that apply to it. Find the <author> tag and replace its text. Find the <title> tag, and replace its text also. Then go to the next book.

However, in your example, writing code to do that is overkill when a simple gsub will do it in one pass:

xml = '<?xml version="1.0"?>
<catalog>
   <book id="bk101">
      <author>AUTHOR1</author>
      <title>TITLE1</title>
      <genre>Computer</genre>
      <price>44.95</price>
      <publish_date>2000-10-01</publish_date>
      <description>An in-depth look at creating applications 
      with XML.</description>
   </book>
   <book id="bk102">
      <author>AUTHOR2</author>
      <title>TITLE2</title>
      <genre>Fantasy</genre>
      <price>5.95</price>
      <publish_date>2000-12-16</publish_date>
      <description>A former architect battles corporate zombies, 
      an evil sorceress, and her own childhood to become queen 
      of the world.</description>
   </book>
 </catalog>
'

values = {
  'TITLE1' => 'Moby Dick',
  'AUTHOR1' => 'Herman Melville',
  'TITLE2' => 'Tom Sawyer',
  'AUTHOR2' => 'Mark Twain',
}

puts xml.gsub(Regexp.union(values.keys), values)
# >> <?xml version="1.0"?>
# >> <catalog>
# >>    <book id="bk101">
# >>       <author>Herman Melville</author>
# >>       <title>Moby Dick</title>
# >>       <genre>Computer</genre>
# >>       <price>44.95</price>
# >>       <publish_date>2000-10-01</publish_date>
# >>       <description>An in-depth look at creating applications 
# >>       with XML.</description>
# >>    </book>
# >>    <book id="bk102">
# >>       <author>Mark Twain</author>
# >>       <title>Tom Sawyer</title>
# >>       <genre>Fantasy</genre>
# >>       <price>5.95</price>
# >>       <publish_date>2000-12-16</publish_date>
# >>       <description>A former architect battles corporate zombies, 
# >>       an evil sorceress, and her own childhood to become queen 
# >>       of the world.</description>
# >>    </book>
# >>  </catalog>

This use of gsub isn't used often, but I've used it many times when substituting values into templates. Using tags/keys that are guaranteed to be unique in the document are essential, so I often flag them using leading and trailing double underscores. In other words __TITLE1__, __AUTHOR1__, etc.

Doing this you can easily replace the content of the other fields, such as <genre>, <price>, etc.

Name the variables in the form the same as the keys/tags, and the task becomes even easier because you should receive a hash of field-names and field-values, which becomes the source for your hash used in the gsub.

Be sure to verify/sanitize the values before substituting. Users mistype and malicious ones can deliberately enter data in an attempt to break your code, or worse, whatever the XML is fed into.

Upvotes: 1

Related Questions