Never been to DZone Snippets before?

Snippets is a public source code repository. Easily build up your personal collection of code snippets, categorize them with tags / keywords, and share them with the world

« Newer Snippets
Older Snippets »
Showing 31-40 of 120 total

Transforming XML into RSS

Using the previous code snippet which prepared an XML file it can now be transformed to RSS using the XSL below.


file: gang2rss.xsl
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

	<xsl:output method="xml" encoding="iso-8859-1" indent="yes"  />

	<xsl:template match="rss">

		<rss version="2.0">	
		<channel>
		<title>The Gang</title>
		<link>http://newsgang.net/audio/</link>
		<description>The Gang podcast</description>

  	<language>en</language>

	<xsl:apply-templates select="item" />

		</channel>
		</rss>

	</xsl:template>

	<xsl:template match="item">

	<item>
		<title><xsl:value-of select="title"/></title>
		<link>http://newsgang.net<xsl:value-of select="href"/></link>
		<description><xsl:value-of select="date"/></description>
		<enclosure>http://newsgang.net<xsl:value-of select="href_audio"/></enclosure>
	</item>

	</xsl:template>	

</xsl:stylesheet>


To transform the xsl file from the command-line you would type:

xsltproc gang2rss.xsl thegang_rss.xml

output
<?xml version="1.0" encoding="iso-8859-1"?>
<rss version="2.0">
  <channel>
    <title>The Gang</title>
    <link>http://newsgang.net/audio/</link>
    <description>The Gang podcast</description>
    <language>en</language>
    <item>
      <title>TheGangXII-II</title>
      <link>http://newsgang.net/gangitem/id=6501</link>
      <description>Jan 25</description>
      <enclosure>http://newsgang.net/gangitem/id=6501&amp;from=audio</enclosure>
    </item>
    <item>
      <title>TheGangXII-I</title>
      <link>http://newsgang.net/gangitem/id=6499</link>
      <description>Jan 25</description>
      <enclosure>http://newsgang.net/gangitem/id=6499&amp;from=audio</enclosure>
    </item>
    <item>
      <title>NewsGangLive01.24.08</title>
      <link>http://newsgang.net/gangitem/id=6445</link>
      <description>Jan 24</description>
      <enclosure>http://newsgang.net/gangitem/id=6445&amp;from=audio</enclosure>
    </item>
    <item>
      <title>NewsGangLiveII</title>
      <link>http://newsgang.net/gangitem/id=6377</link>
      <description>Jan 23</description>
      <enclosure>http://newsgang.net/gangitem/id=6377&amp;from=audio</enclosure>
    </item>
  </channel>
</rss>

Note: The enclosure url in this example does not reference the media file directly.

see also: http://en.wikipedia.org/wiki/RSS_(file_format)

Outputting XML as text within XML

Return XML from the web server, and make the XML with result tags simple text. Using HTTP.responseXML the result xmldoc.documentElement.firstChild.nodeValue was then passed into a textarea.

require 'cgi'

cgi = CGI.new

puts "Content-Type: text/xml"
puts

print "<result>"
print "<![CDATA[<a>123</a>]]>" 
print "</result>"


Using the XSLT sum function

This XML and XSLT code is an example of storing and displaying a car mileage log. Notably the XSLT sum() function displays the total no of miles.


file: car_log.xsl
<?xml version="1.0"?>

    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
      
    <xsl:template match="car_log">
      <div>      
        <p>Total miles this month: <xsl:value-of select="sum(records/entry/miles)" /></p>
        <xsl:apply-templates select="records"/>
      </div>
    </xsl:template>
    
    <xsl:template match="car_log/records/entry"><xsl:variable name="pos" select="position()"/>
    <div class="record">
      <dl>
        <dt><label for="trip"><xsl:value-of select="@title"/>trip</label></dt>
        <dd>
          <input type="text" id="trip{$pos}" name="trip{$pos}" value="{trip}" size="{@size}" />
        </dd>
          
        <dt><label for="miles"><xsl:value-of select="@title"/>miles</label></dt>
        <dd>
          <input type="text" id="miles{$pos}" name="miles{$pos}" value="{miles}" size="2" />
        </dd>
          
        <dt><label for="description"><xsl:value-of select="@title"/>description</label></dt>
        <dd>
          <input type="text" id="description{$pos}" name="description{$pos}" value="{description}"  />
        </dd>        
      </dl>
    </div>
    </xsl:template>
    </xsl:stylesheet>

file: car_log.xml
<car_log>
  <summary>
    <project>car_log</project>
  </summary>
  <records>
    <entry id='17962'><date>Wed Dec 12 20:00:33 +0000 2007</date><trip>trip to the supermarket</trip><miles>11.8</miles><description>my first trip with the GPS installed</description></entry>
    <entry id='18024'><date>Fri Dec 14 11:45:09 +0000 2007</date><trip>driving around the park</trip><miles>26.1</miles><description/></entry>
    <entry id='18173'><date>Thu Dec 20 01:21:27 +0000 2007</date><trip>trip to the supermarket</trip><miles> 8.5</miles><description/></entry>
    <entry id='18174'><date>Thu Dec 20 01:34:26 +0000 2007</date><trip>visiting parents</trip><miles>12.7</miles><description/>
    </entry>
  </records>
</car_log>

output
Total miles this month: 59.1
...

Setting a string variable with a mult-line text value

This example demonstrates how easy it is to copy and paste human-readable text from elsewhere and declare it as a string in your code.

string = <<RUBY_RUBY_RUBY
  <mydoc>
    <someelement attribute="nanoo">Text, text, text</someelement>
  </mydoc>
RUBY_RUBY_RUBY



Note: Remember to encase the text within a pair of strings, any string (the convention is to make it uppercase) and ensure it's not a reserved keyword, or a variable declared already.

Pretty Print XML using Ruby

This code makes the XML output look pretty. I tried using the documentation from the REXML website to apply the method example doc.write($stdout,0), but I gave up, and instead wrote my own XML pretty-print method.

require 'rexml/document'
include REXML

  def pretty_print(parent_node, itab)
    buffer = ''

    parent_node.elements.each do |node|

      buffer += ' ' * itab + "<#{node.name}#{get_att_list(node)}"
  
      if node.to_a.length > 0
        buffer += ">"
        if node.text.nil?
          buffer += "\n"
          buffer += pretty_print(node,itab+2) 
          buffer += ' ' * itab + "</#{node.name}>\n"
        else
          node_text = node.text.strip
          if node_text != ''
            buffer += node_text 
            buffer += "</#{node.name}>\n"        
          else
            buffer += "\n" + pretty_print(node,itab+2) 
            buffer += ' ' * itab + "</#{node.name}>\n"        
          end
        end
      else
        buffer += "/>\n"
      end
      
    end
    buffer
  end

  def get_att_list(node)
    att_list = ''
    node.attributes.each { |attribute, val| att_list += " #{attribute}='#{val}'" }
    att_list
  end
  
  def pretty_xml(doc)
    buffer = ''
    xml_declaration = doc.to_s.match('<\?.*\?>').to_s
    buffer += "#{xml_declaration}\n" if not xml_declaration.nil?
    xml_doctype = doc.to_s.match('<\!.*\">').to_s
    buffer += "#{xml_doctype}\n" if not xml_doctype.nil?
    buffer += "<#{doc.root.name}#{get_att_list(doc.root)}"
    if doc.root.to_a.length > 0
      buffer +=">\n#{pretty_print(doc.root,2)}</#{doc.root.name}>"
    else
      buffer += "/>\n"
    end
  end

xml_data = "<hi id='124'><yo><a id='1'/><b/><c/></yo><sushi><love>Ruby</love></sushi></hi>"
doc = Document.new(xml_data)
pretty_xml(doc)


output
<hi id='124'>
  <yo>
    <a id='1'/>
    <b/>
    <c/>
  </yo>
  <sushi>
    <love>Ruby</love>
  </sushi>
</hi>


*Update 7-Jan-08 1:51AM *
Although I haven't tried running the following XSL code, this might actually have been a better solution to my problem. source: http://www.printk.net/~bds/indent.html

*Pretty Print XML using XSLT*
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" encoding="ISO-8859-1"/>
  <xsl:param name="indent-increment" select="'   '"/>
  
  <xsl:template name="newline">
    <xsl:text disable-output-escaping="yes">
</xsl:text>
  </xsl:template>
  
  <xsl:template match="comment() | processing-instruction()">
    <xsl:param name="indent" select="''"/>
    <xsl:call-template name="newline"/>    
    <xsl:value-of select="$indent"/>
    <xsl:copy />
  </xsl:template>
  
  <xsl:template match="text()">
    <xsl:param name="indent" select="''"/>
    <xsl:call-template name="newline"/>    
    <xsl:value-of select="$indent"/>
    <xsl:value-of select="normalize-space(.)"/>
  </xsl:template>
    
  <xsl:template match="text()[normalize-space(.)='']"/>
  
  <xsl:template match="*">
    <xsl:param name="indent" select="''"/>
    <xsl:call-template name="newline"/>    
    <xsl:value-of select="$indent"/>
      <xsl:choose>
       <xsl:when test="count(child::*) > 0">
        <xsl:copy>
         <xsl:copy-of select="@*"/>
         <xsl:apply-templates select="*|text()">
           <xsl:with-param name="indent" select="concat ($indent, $indent-increment)"/>
         </xsl:apply-templates>
         <xsl:call-template name="newline"/>
         <xsl:value-of select="$indent"/>
        </xsl:copy>
       </xsl:when>       
       <xsl:otherwise>
        <xsl:copy-of select="."/>
       </xsl:otherwise>
     </xsl:choose>
  </xsl:template>    
</xsl:stylesheet>

Count the no of elements in an XML node

This Ruby code count the no. of elements in an xml node by converting the children into an array and then returning the length.

require 'rexml/document'
include REXML

file = File.new('test.xml')
doc = Document.new(file)
puts doc.root.elements.to_a.length

Generate an XSL file for a simple XML file

Using Ruby and XSLT this code creates an xsl file for a corresponding xml file. Note: It only reproduces xml elements in the xsl file, not element attributes.
#!/usr/bin/ruby
# file: xml2xsl.rb

# author: jrobertson
# created: 31-Dec-07
# description: 
#   Converts an xml file into another xml file in 'xml2xsl' format.
#   This new xml file can then be transformed with the stylesheet 
#   xml2xsl.xsl into a multi-purpose xsl file template for the original 
#   xml file.

 
require 'rexml/document'
include REXML

class PreXml2Xsl

  def pre_xml2xsl(doc)
    puts '<xsl>'
    puts "  <template name='" + doc.root.name + "'>"
    build_xml(doc.root)
    puts '    </template>'
    puts '</xsl>'
  end
  
  def build_xml(node)
    previous_name = ''
    node.each_child do |child| 
      if child.length > 1 
        build_template(child.name)
        build_xml(child) 
      else
        build_value(child.name) if child.name != previous_name
        previous_name = child.name
      end
    end
  end
      
  def build_template(element)
    puts '  ' + "<select name=\"#{element}\" />"
    puts "</template>"
    puts "<template name=\"#{element}\">"
  end

  def build_value(element)
    puts '  ' + "<value name=\"#{element}\" />"
  end

  if __FILE__ == $0
    xml_language = '<languages><programming><name>C++</name><name>C Sharp</name
><name>Ruby</name></programming></languages>'
    doc = Document.new(xml_language)
    px = PreXml2Xsl.new
    px.pre_xml2xsl(doc)
  end
end

file: xml2xsl.xml (output from xml2xsl.rb)
<xsl>
  <template name="languages">
    <select name="programming"/>
  </template>
  <template name="programming">
    <value name="name"/>
  </template>
</xsl>

file: xml2xsl.xsl (used with xml2xsl.xml)
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

  <xsl:template match="xsl">
  <xsl:variable name="colon"><xsl:text>:</xsl:text></xsl:variable>
    <xsl:element name="xsl:stylesheet">
      <xsl:attribute name="xmlns{$colon}xsl">
        <xsl:text>http://www.w3.org/1999/XSL/Transform</xsl:text>
      </xsl:attribute>
      <xsl:attribute name="version">
        <xsl:text>1.0</xsl:text>
      </xsl:attribute>
      
      <xsl:apply-templates select="*" />
    
  </xsl:element>

  </xsl:template>
  
  <xsl:template match="template">
  <xsl:text>
  </xsl:text>
        <xsl:element name="xsl:template">
        <xsl:attribute name="match">
          <xsl:value-of select="@name"/>
        </xsl:attribute>

        <xsl:apply-templates select="*" />
  <xsl:text>
  </xsl:text>
    </xsl:element>
<xsl:text>
</xsl:text>

  </xsl:template>
  
  <xsl:template match="select">
    <xsl:text>
    </xsl:text>
  <xsl:element name="xsl:element">
    <xsl:attribute name="name">
      <xsl:value-of select="@name"/>
    </xsl:attribute>
    <xsl:text>
    </xsl:text>
    <xsl:text>  </xsl:text><xsl:element name="xsl:apply-templates">
      <xsl:attribute name="select">
        <xsl:value-of select="@name"/>
      </xsl:attribute>
    </xsl:element>
    <xsl:text>
    </xsl:text>
  </xsl:element>


  </xsl:template>
  
  <xsl:template match="value">
    <xsl:text>
    </xsl:text>
  <xsl:element name="xsl:element">
    <xsl:attribute name="name">
      <xsl:value-of select="@name"/>
    </xsl:attribute>
      <xsl:text>
      </xsl:text>
    <xsl:element name="xsl:value-of">
      <xsl:attribute name="select">
        <xsl:value-of select="@name"/>
      </xsl:attribute>
    </xsl:element>
    <xsl:text>
    </xsl:text>
  </xsl:element>
</xsl:template>
</xsl:stylesheet>

output from xml2xsl.xsl
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  <xsl:template match="languages">
    <xsl:element name="programming">
      <xsl:apply-templates select="programming"/>
    </xsl:element>
  </xsl:template>

  <xsl:template match="programming">
    <xsl:element name="name">
      <xsl:value-of select="name"/>
    </xsl:element>
  </xsl:template>
</xsl:stylesheet>

Mark directories to be deleted based on their date-stamp

This Ruby code selects file directories which are older than a certain date and outputs an XML file naming all the directories to be removed. It does this by reading a directory listing formatted within the XML file 'dir.xml', all directories are named by a date-stamp, which is used to determine if the directory should be removed.

This example is used to maintain the webcamera (named 'pear') which saves it's images to a date-stamped directory daily. Any directory which is older than 14 days will be marked for deletion.

  def directory_housekeeping()
    lifespan = 14
    format_mask = 'm_d_y'
    separator = format_mask.match(/[\_*\-]/).to_s
    
    earliest_date = Time.now + (60 * 60 * 24) * -lifespan
    cut_off_date = Date.new(y=earliest_date.year,m=earliest_date.month,d=earliest_date.day)
        
    a_format = Array.new
    a_format[0] = format_mask.match(/^[y,m,d]*/).to_s
    a_format[1] = format_mask.match(separator + '[y,m,d]*').to_s.gsub(separator,'')
    a_format[2] = format_mask.match('[y,m,d]$').to_s
    
    file = File.new('../housekeeping/webcam_pear/dir.xml')
    ddoc = REXML::Document.new(file)
    file.close
    
    file_delete = File.new('../housekeeping/webcam_pear/files2delete.xml', 'w')
    doc_delete = Document.new()
    doc_delete.add_element('files')
    
    ddoc.root.elements.each('file') do |file_node|
      sfile = file_node.text
      idate = Array.new
      idate[0] = sfile.match(/^\d*/).to_s.to_i
      idate[1] = sfile.match(/\_\d*/).to_s.gsub(separator,'').to_i
      idate[2] = sfile.match(/\_\d*\d$/).to_s.gsub(separator,'').to_i

      h = Hash.new
      0.upto(2) {|i| h[a_format[i]] = idate[i]}

      file_date = Date.new(y=h['y'], m=h['m'], d=h['d'])

      if file_date < cut_off_date
        o_file2delete = Element.new('file')
        o_file2delete.text = file_date.strftime(dformat)
        doc_delete.root.add_element o_file2delete
      end
    end
    file_delete.puts doc_delete
  end



file: dir.xml
<dir>
  <file>11_4_2007</file>
  <file>11_5_2007</file>
  <file>11_6_2007</file>
  <file>11_7_2007</file>
  <file>11_8_2007</file>
  <file>11_9_2007</file>
  <file>12_10_2007</file>
  <file>12_11_2007</file>
  <file>12_1_2007</file>
  <file>12_12_2007</file>
  <file>12_13_2007</file>
  <file>12_14_2007</file>
  <file>12_15_2007</file>
  <file>12_16_2007</file>
  <file>12_17_2007</file>
  <file>12_18_2007</file>
  <file>12_19_2007</file>
  <file>12_20_2007</file>
  <file>12_21_2007</file>
  <file>12_2_2007</file>
  <file>12_22_2007</file>
  <file>12_23_2007</file>
  <file>12_24_2007</file>
  <file>12_25_2007</file>
  <file>12_26_2007</file>
  <file>12_27_2007</file>
  <file>12_28_2007</file>
  <file>12_3_2007</file>
  <file>12_4_2007</file>
  <file>12_5_2007</file>
  <file>12_6_2007</file>
  <file>12_7_2007</file>
  <file>12_8_2007</file>
  <file>12_9_2007</file>
 </dir>

file: files2delete.xml
<files>
  <file>11_4_2007</file>
  <file>11_5_2007</file>
  <file>11_6_2007</file>
  <file>11_7_2007</file>
  <file>11_8_2007</file>
  <file>11_9_2007</file>
  <file>12_10_2007</file>
  <file>12_11_2007</file>
  <file>12_1_2007</file>
  <file>12_12_2007</file>
  <file>12_13_2007</file>
  <file>12_14_2007</file>
  <file>12_15_2007</file>
  <file>12_2_2007</file>
  <file>12_3_2007</file>
  <file>12_4_2007</file>
  <file>12_5_2007</file>
  <file>12_6_2007</file>
  <file>12_7_2007</file>
  <file>12_8_2007</file>
  <file>12_9_2007</file>
 </files>

Create a crontab entry using XML

This code creates a formatted crontab entry using the files crontab.xml, and crontab_txt.xsl. It is intended that all cron jobs could be stored in the crontab.xml file and then passed to the crontab.

file: crontab_txt.xsl
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="text"/>

  <xsl:template match="crontab_entry">

  <xsl:apply-templates select="minutes"/>
  <xsl:apply-templates select="hours"/>
  <xsl:apply-templates select="day_of_month"/>
  <xsl:apply-templates select="months"/>
  <xsl:apply-templates select="day_of_week"/>

  <xsl:value-of select="command" />
  </xsl:template>
  
  <xsl:template match="minutes">
    <xsl:apply-templates select="minute"/>
    <xsl:if test="not(minute) or minute=''">*</xsl:if>
    <xsl:call-template name="format_unit" />
  </xsl:template>
  
  <xsl:template match="hours">
    <xsl:apply-templates select="hour"/>
    <xsl:if test="not(hour) or hour=''">*</xsl:if>
    <xsl:call-template name="format_unit" />
  </xsl:template>
  
  <xsl:template match="day_of_month">
    <xsl:apply-templates select="day"/>
    <xsl:if test="not(day) or day=''">*</xsl:if>
    <xsl:call-template name="format_unit" />
  </xsl:template>
  
  <xsl:template match="day_of_week">
    <xsl:apply-templates select="day"/>
    <xsl:if test="not(day) or day=''">*</xsl:if>
    <xsl:call-template name="format_unit" />
  </xsl:template>
  
  <xsl:template match="months">
    <xsl:apply-templates select="month"/>
    <xsl:if test="not(month) or month=''">*</xsl:if>
    <xsl:call-template name="format_unit" />
  </xsl:template>
    
  <xsl:template match="month">
    <xsl:call-template name="format_value" />
  </xsl:template>
  
  <xsl:template match="day">
    <xsl:call-template name="format_value" />
  </xsl:template>
  
  <xsl:template match="hour">
    <xsl:call-template name="format_value" />
  </xsl:template>
  
  <xsl:template match="minute">
    <xsl:call-template name="format_value" />
  </xsl:template>
  
  <xsl:template name="format_value">
    <xsl:value-of select="."/>
    <xsl:if test="not(position() =last())"><xsl:text>,</xsl:text>
    </xsl:if>
  </xsl:template>
  
  <xsl:template name="format_unit">
    <xsl:call-template name="recurring" />
    <xsl:text> </xsl:text>
  </xsl:template>
  
  <xsl:template name="recurring">
    <xsl:if test="@every">/<xsl:value-of select="@every"/>
    </xsl:if>
  </xsl:template>
  
</xsl:stylesheet>

file: crontab.xml
<crontab_entry>
  <minutes/>
  <hours every="3">
  <day_of_month>
    <day>3</day>
    <day>10</day>
    <day>15</day>
  </day_of_month>
  <months/>
  <day_of_week/>
  <command>ssh james@192.168.1.220 runjob.sh</command>
</crontab_entry>

output: * */3 3,10,15 * * ssh james@192.168.1.220 runjob.sh

A helpful crontab.xml template
<cron>
  <minutes>
    <!-- minute (0 - 59) -->
    <minute></minute>
  </minutes
  <hours>
    <!-- hour (0 -23) -->
    <hour></hour>
  </hours>
  <day_of_month>
    <!-- day of month (1 - 31) -->
    <day></day>
  </day_of_month>
  <months>
    <!-- month (1 - 12) -->
    <month></month>
  </months>
  <day_of_week>
   <!-- day of week (0 - 6) (Sunday=0 or 7) -->
   <day></day>
  </day_of_week>
  <command></command>
</cron>

Supplying parameters to Ruby XSLT

Here the parameters are supplied as a hash, and if the parameters are not supplied the method will process the xml, and xsl files as normal.

require 'xml/xslt'

class Projxslt
  
  def initialize(sxml, sxsl)
    @sxml = sxml
    @sxsl = sxsl
  end

  def transform(h=nil)
    begin
    xslt = XML::XSLT.new() 
    xslt.xml = @sxml
    xslt.xsl = @sxsl

    if not h.nil? then xslt.parameters = h end
    out = xslt.serve()
    out
    
    rescue
      puts 'problem with xslt data'
    end
  end

end

if __FILE__ == $0
    h = Hash.new
    h["id"] = '1'
    puts h
    pxsl = Projxslt.new("../recordx/recordx.xml", "../xsl/recordx.xsl")
    puts pxsl.transform(h)
end
« Newer Snippets
Older Snippets »
Showing 31-40 of 120 total