Skip to main content

By clicking Submit, you agree to the developerWorks terms of use.

The first time you sign into developerWorks, a profile is created for you. Select information in your developerWorks profile is displayed to the public, but you may edit the information at any time. Your first name, last name (unless you choose to hide them), and display name will accompany the content that you post.

All information submitted is secure.

  • Close [x]

The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerworks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

By clicking Submit, you agree to the developerWorks terms of use.

All information submitted is secure.

  • Close [x]

XForms as an RSS reader/editor

Nicholas Chase (ibmquestions@nicholaschase.com), Freelance writer, Backstop Media
Nicholas Chase has been involved in Web site development for companies such as Lucent Technologies, Sun Microsystems, Oracle, and the Tampa Bay Buccaneers. Nick has been a high school physics teacher, a low-level radioactive waste facility manager, an online science fiction magazine editor, a multimedia engineer, an Oracle instructor, and the Chief Technology Officer of an interactive communications company. He is the author of several books, including XML Primer Plus (Sams).

Summary:  RSS, Atom, and other syndication strategies involve making XML data available for download. XForms, which is designed to view and edit XML, is the perfect environment for an XML editor and reader. This article explains how to create an XML reader and editor using XForms.

Date:  30 Jan 2007
Level:  Intermediate
Also available in:   Chinese  Japanese

Activity:  7143 views
Comments:  

Introduction

This article assumes that you are familar with the basics of XForms and at least one syndication format such as RSS. The article uses RSS 1.0, but the concepts are the same for not only any version of RSS, but also Atom and any other XML-based format. The code was tested using Mozilla Firefox with the XForms extension (see Resources), but the concept should work in any XForms-capable browser.


What you're trying to accomplish

The idea is to create a page that enables the user to request a specific feed to read based on its URL, displaying its information on the page, as shown in Figure 1.


Figure 1. The reader
The reader

The page also includes a button that lets the reader switch to an editor, as shown in Figure 2.


Figure 2. The editor
The editor

Loading external URLs

As a security measure, the XForms extension only loads data from and sends data to URLs on the same server from which the form was loaded. For editing, this makes sense, but if you want to be able to read external feeds, you'll need to set permissions in your browser. To do that, choose Tools > Options and click the Allow XForms to access other domains checkbox. Click the Allowed Sites button to add domains from which you want to load data.

The editor enables the user to change existing information, add a new item, delete existing items, and save the feed, assuming that you have the appropriate permissions.


The basic form

The first step is to create the basic page that enables the user to specify a feed to read. To do that, start with a basic XForms form, embedded in an XHTML page (see Listing 1).


Listing 1.The most basic form
                
<?xml version="1.0" encoding="ASCII"?>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:xforms="http://www.w3.org/2002/xforms">
  <head>
    <title>RSS Reader</title>

<xforms:model>
                <xforms:instance id="content" src="blankfeed.xml" />
                </xforms:model>

    <link href="gen_default.css" rel="stylesheet"/>

  </head>
  <body>

<h1>The XForms Feed Reader</h1>

  </body>
</html>

The form doesn't specify any visible controls, but it does create the model and the instance, which will ultimately define the data the user sees. The blankfeed.xml file is a placeholder that contains only enough structure to make sure the controls you ultimately build can bind properly, as shown in Listing 2.


Listing 2. The blankfeed.xml file
                
<?xml version="1.0" encoding="UTF-8"?>
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" 
xmlns:dc="http://purl.org/dc/elements/1.1/" 
xmlns="http://purl.org/rss/1.0/">

<channel rdf:about="">
<title></title>
<link></link>
<description></description>
<dc:language>en-us</dc:language>
<dc:creator />
<dc:date></dc:date>

<items>
<rdf:Seq>
</rdf:Seq>
</items>

</channel>

</rdf:RDF>

Now you need a way for the user to specify the feed with which he or she wants to work. Fortunately, you can take advantage of how XForms works to accomplish this task. You're probably already aware of how changing a value in one XForms control can lead to the browser automatically displaying new information somewhere else. What you might not know is that the XForms processor reacts that way to virtually any change. For example, you can create a form that automatically changes the value of the instance element's src attribute (see Listing 3).


Listing 3. Requesting a new feed
                
...
<h1>The XForms Feed Reader</h1>

<p>Enter the URL of a feed to read:
                <form name="urlform" id="urlform" 
                   onsubmit="document.getElementById('content').setAttribute('src',>
                                document.forms['urlform'].elements['targeturl'].value);
                                return false;">
                    <input type="text" name="targeturl" id="targeturl" />
                   <input type="submit" value="go" />
                </form>
                </p>

  </body>
</html>

The form doesn't actually take the browser to a new page. Instead, it acts as a way to execute a bit of JavaScript code. The user enters a URL in the targeturl field, and when he or she submits the form, either by clicking the Enter key or by clicking the Submit button, the browser executes the onsubmit handler. That script gets a reference to the src attribute of the instance by referencing its id attribute, content. From there, it sets that value to match the text entered in the targeturl field.

Once that value changes, the instance gets reloaded. You can load the page and submit the form, but in order to see any changes, you'll have to add some visible controls.


XForms as an RSS reader

Creating the reader part of the page is very straightforward. You are dealing with a well-known format, in this case RSS 1.0 (see Listing 4).


Listing 4. The target file
                
<?xml version="1.0" encoding="UTF-8"?>
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" 
xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns="http://purl.org/rss/1.0/">

<channel rdf:about="http://www.chaosmagnet.com/blog/">
<title>Chaos Magnet</title>
<link>http://www.chaosmagnet.com/blog/</link>
<description>The personal and professional ramblings of technology 
author Nicholas Chase.</description>
<dc:language>en-us</dc:language>
<dc:creator />
<dc:date>2006-12-22T09:53:16-05:00</dc:date>

<items>
<rdf:Seq>
<rdf:li rdf:resource="http://www.chaosmagnet.com/blog/archives/000840.html" />
<rdf:li rdf:resource="http://www.chaosmagnet.com/blog/archives/000839.html" />
...
</rdf:Seq>
</items>

</channel>

<item rdf:about="http://www.chaosmagnet.com/blog/archives/000840.html">
<title>A quick hit on Rick Berman</title>
<link>http://www.chaosmagnet.com/blog/archives/test.html</link>
<description>I believe in reading source material, but I just can't bring myself to 
do it in this case. Not for just one quick comment. SyFy Portal has a discussion 
of an interview 
with Rick Berman, from a transcript of a...</description>
<dc:subject>Rants</dc:subject>
<dc:creator>roadnick</dc:creator>
<dc:date>2006-12-22T09:53:16-05:00</dc:date>
</item>

<item rdf:about="http://www.chaosmagnet.com/blog/archives/000839.html">
<title>Now everyone can add "and 2006 Time's Person Of The Year"  to their bio</title>
<link>http://www.chaosmagnet.com/blog/archives/000839.html</link>
<description>It may sound a little silly, but that's what Time did for 
2006, in choosing it's 
Person of the Year. The premise is that ...</description>
<dc:subject>Fun stuff</dc:subject>
<dc:creator>roadnick</dc:creator>
<dc:date>2006-12-21T09:00:21-05:00</dc:date>
</item>
...
</rdf:RDF>

The file includes a variety of namespaces, including RSS, the Dublin Core, and RDF. You'll need to take that into account when creating the XForms form. The reader form itself is very straightfoward (see Listing 5).


Listing 5. The reader form
                
...
    <input type="submit" value="go" />
</form>
</p>

    <h1 align="center"><xforms:output 
                ref="/rdf:RDF/rss:channel/rss:title" /></h1>
                <xforms:repeat nodeset="/rdf:RDF/rss:item">
                  <h2><xforms:output ref="rss:title"/></h2>
                  <xforms:output ref="rss:description"/>
                  <xforms:output ref="rss:link"/>
                  <xforms:output ref="dc:date" />
                  <i><xforms:output ref="dc:subject" /></i>
                </xforms:repeat>

  </body>
</html>

First, you display a title on the page by working your way down into the title included as part of the channel element. Notice the use of namespace prefixes. Even though the elements in the RSS namespace didn't have prefixes in the original file, they still belong to that namespace. Because this file uses XHTML as the default namespace, you'll need to use the rss: prefix to specify the RSS elements.

You'll use the repeat element to loop through each of the rss:item elements. Finally, use the output element to display individual items and their information.

The result, styled using CSS, looks like Figure 3.


Figure 3. The reader
The reader

Okay, that was simple enough. You can, of course, do more complex formatting and layout, but this is the basic method.

But what about editing?


Editing items

Editing items is also fairly straightforward, as you can see in Listing 6.


Listing 6. Editing items
                
    <h1 align="center"><xforms:output ref="/rdf:RDF/rss:channel/rss:title" /></h1>

<xforms:repeat id="itemlist" nodeset="/rdf:RDF/rss:item">
                   <xforms:input ref="rss:title">
                    <xforms:label>Title: </xforms:label>
                  </xforms:input>
                  <xforms:input ref="rss:description">
                     <xforms:label>Excerpt: </xforms:label>
                   </xforms:input>
                   <xforms:input ref="rss:link">
                      <xforms:label>URL</xforms:label>
                   </xforms:input>
                   <xforms:input ref="dc:subject">
                     <xforms:label>Category</xforms:label>
                   </xforms:input>
                   <xforms:input ref="dc:date">
                      <xforms:label>Created</xforms:label>
                   </xforms:input>

</xforms:repeat>

<xforms:repeat nodeset="/rdf:RDF/rss:item">
  <h2><xforms:output ref="rss:title"/></h2>
...

Once again, you loop through the individual rss:item elements, this time using input elements rather than output elements. You'll give the repeat element an id value so you can refer to it later. The result looks like Figure 4.


Figure 4. The editor
The editor

Now, this makes it easy to edit visible data, but what about data that's not immediately obvious, such as the rdf:about attribute or the rdf:Seq list that appears at the top of the file?


Automatically updating values

RSS 1.0 includes a separate section that lists the URLs of individual items, and an attribute that also lists the URL. You need to make sure that if the URL is changed in the form, this information propogates to these nodes. To do that, you can use a combination of techniques (see Listing 7).


Listing 7. Updating values
                
...
<xforms:model>
  <xforms:instance id="content" src="samplerssfeed.xml" />
  <xforms:bind nodeset="/rdf:RDF/rss:item/@rdf:about" calculate="../rss:link" />
                </xforms:model>

...
   <xforms:input ref="rss:link">
      <xforms:label>URL</xforms:label>
      <xforms:action ev:event="xforms-value-changed">>
                  <xforms:setvalue 
                 ref="/rdf:RDF/rss:channel/rss:items/rdf:Seq/rdf:li[index('itemlist')]
                   /@rdf:resource" 
                   value="/rdf:RDF/rss:item[index('itemlist')]/rss:link" />
                 </xforms:action>
   </xforms:input>
   <xforms:input ref="dc:subject">
...

It's easy to keep the rdf:about attribute in sync; you can use use a bind element. This element makes sure that no matter what you do, the value of a particular item's rdf:about attribute always matches the value of its rss:link child.

The rdf:Seq list is another matter; because they are in different parts of the DOM, you can't use a simple bind element. For this list, you will need to listen for the event that signifies that the value of the rss:link field has been changed, and when it has, you need to manually reset the rdf:li element, using the index of the repeat element -- remember how you gave it an id value to refer to it later? -- to coordinate positions.

Now you need to save the feed.


Saving the feed

Saving the feed is a matter of creating a submission element that sends the instance data to a script that can save it (see Listing 8).


Listing 8. Creating a submission element
                
...
<xforms:model>
  <xforms:instance id="content" src="samplerssfeed.xml" />
  <xforms:submission id="submitrsstosave" action="http://localhost/rssxforms.php"
                        instance="content" replace="instance"       method="post"/>
  <xforms:bind nodeset="/rdf:RDF/rss:item/@rdf:about" calculate="../rss:link" />
</xforms:model>
...
    <h1 align="center"><xforms:output ref="/rdf:RDF/rss:channel/rss:title" /></h1>

    <xforms:submit submission="submitrsstosave">
               <xforms:label>Save Feed</xforms:label>
               </xforms:submit>

<xforms:repeat id="itemlist" nodeset="/rdf:RDF/rss:item">
...

You don't want the entire page to go anywhere when the user saves the feed, so just replace the instance. The target of this submission is a simple script that reads the data, saves it, and echoes it back out for the instance to re-populate itself (see Listing 9).


Listing 9. The script to save the data
                
<?php
if (!isset($HTTP_RAW_POST_DATA))
   $HTTP_RAW_POST_DATA = file_get_contents("php://input");

$filename = "C:/SW/public_html/savedfeed.xml";

$fh = fopen($filename, 'w');
fwrite($fh, $HTTP_RAW_POST_DATA);
fclose($fh);

header("Content-type: text/plain");
echo $HTTP_RAW_POST_DATA;
?>

In this case, you're saving the file to a specific location, independent of the actual URL for the feed. In an actual application, you'll likely want to base the location of the saved file on the actual feed itself. Most feeds include their original location. For example, your sample feed lists the original location in the rdf:RDF/rss:link element.

You can also use the PUT method if your server supports it.

Now let's look at adding items to the feed.


Adding new items

Adding new items is a matter of adding an "insert" button with the appropriate action (see Listing 10).


Listing 10. Adding new items
                
...
    <h1 align="center"><xforms:output ref="/rdf:RDF/rss:channel/rss:title" /></h1>

    <xforms:trigger>
              <xforms:label>Add New item</xforms:label>
            <xforms:action ev:event="DOMActivate">
            <xforms:insert nodeset="/rdf:RDF/rss:item" at="1" position="before"/>
           <xforms:setvalue ref="/rdf:RDF/rss:item[1]/@rdf:about" />
           <xforms:setvalue ref="/rdf:RDF/rss:item[1]/rss:title" />
           <xforms:setvalue ref="/rdf:RDF/rss:item[1]/rss:link" />
           <xforms:setvalue ref="/rdf:RDF/rss:item[1]/rss:description" />
            <xforms:setvalue ref="/rdf:RDF/rss:item[1]/dc:subject" />
            <xforms:setvalue ref="/rdf:RDF/rss:item[1]/dc:date" value="now()" />
             <xforms:insert nodeset="/rdf:RDF/rss:channel/rdf:Seq/rdf:li" at="1" 
                 position="before"/>
               <xforms:setvalue ref="/rdf:RDF/rss:channel/rdf:Seq/rdf:li/@rdf:resource" />
                </xforms:action>  
            </xforms:trigger>

    <xforms:submit submission="submitrsstosave">
      <xforms:label>Save Feed</xforms:label>
    </xforms:submit>
...

When the user clicks the Add New Item button, it clones the last rdf:RDF/rss:item element and adds the clone before the first existing one. Because it includes the old data, however, you need to use the setvalue element to clear out the existing data. The one exception to this rule is the dc:date value, which you can set using the now() function, part of XForms. (You may also want to set this value when any of the other data changes, but I'll leave that as an exercise for you, the reader.)

You also need to add the rdf:li node to the top of the file and clear its rdf:resource attibute.


Deleting items

Finally, you need to give the user the ability to delete individual items (see Listing 11).


Listing 11. Deleting individual items
                
...
   <xforms:input ref="dc:date">
      <xforms:label>Created</xforms:label>
   </xforms:input>
   <xforms:trigger>
                 <xforms:label>Delete</xforms:label>
                 <xforms:action ev:event="DOMActivate">
                    <xforms:delete nodeset="." at="1" />
                 </xforms:action>  
                 </xforms:trigger>

</xforms:repeat>
...

Because you're including the trigger right in the repeat, deciding which element to delete is easy; it's always the current one.


Deciding which form to show

The final step is to give the user control over which form to use. When the form first loads, you want the user to see the "reader," but you want him or her to have the ability to change over to the "editor" view and back (see Listing 12).


Listing 12. Choosing the form
                
...
    <h1 align="center"><xforms:output ref="/rdf:RDF/rss:channel/rss:title" /></h1>

<xforms:switch>
                <xforms:case id="edit" selected="false">
                   <xforms:trigger id="readButton">
                  <xforms:label>Reader</xforms:label>
                  <xforms:toggle ev:event="DOMActivate" 
                case="read"/>
                </xforms:trigger>


    <xforms:trigger>
      <xforms:label>Add New item</xforms:label>
      <xforms:action ev:event="DOMActivate">
...
      <xforms:delete nodeset="." at="1" />
    </xforms:action>  
  </xforms:trigger>

</xforms:repeat>

  </xforms:case>
                <xforms:case id="read" selected="true">
                   <xforms:trigger id="editButton">
                    <xforms:label>Editor</xforms:label>
                    <xforms:toggle ev:event="DOMActivate" 
                case="edit"/>
                </xforms:trigger>

<xforms:repeat nodeset="/rdf:RDF/rss:item">
  <h2><xforms:output ref="rss:title"/></h2>
   <xforms:output ref="rss:description"/>
   <xforms:output ref="rss:link"/>
   <xforms:output ref="dc:date" />
     <i><xforms:output ref="dc:subject" /></i>
</xforms:repeat>

  </xforms:case>
                </xforms:switch>

  </body>
</html>

The switch element works like a case statement in other programming languages. Here you're starting with a case of "read" -- using selected="true" -- and adding a trigger that enables the user to toggle that value to edit. When the user clicks it, the case, and therefore the view, changes. The edit case is similar, toggling over to the reader form.


Summary

XForms provides an excellent basis for editing RSS, Atom, and other XML-based syndication formats. In this article, you created a form that enables the user to choose a feed, read it, edit it, and save it to a file. In a production application, you will also need to determine the version of the feed at hand and alter your forms accordingly.



Download

DescriptionNameSizeDownload method
XForms RSS Reader source coderssreader_source.zip5KB HTTP

Information about download methods


Resources

Learn

Get products and technologies

Discuss

About the author

Nicholas Chase has been involved in Web site development for companies such as Lucent Technologies, Sun Microsystems, Oracle, and the Tampa Bay Buccaneers. Nick has been a high school physics teacher, a low-level radioactive waste facility manager, an online science fiction magazine editor, a multimedia engineer, an Oracle instructor, and the Chief Technology Officer of an interactive communications company. He is the author of several books, including XML Primer Plus (Sams).

Report abuse help

Report abuse

Thank you. This entry has been flagged for moderator attention.


Report abuse help

Report abuse

Report abuse submission failed. Please try again later.


developerWorks: Sign in


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Select information in your developerWorks profile is displayed to the public, but you may edit the information at any time. Your first name, last name (unless you choose to hide them), and display name will accompany the content that you post.

Choose your display name

The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


Rate this article

Comments

Help: Update or add to My dW interests

What's this?

This little timesaver lets you update your My developerWorks profile with just one click! The general subject of this content (AIX and UNIX, Information Management, Lotus, Rational, Tivoli, WebSphere, Java, Linux, Open source, SOA and Web services, Web development, or XML) will be added to the interests section of your profile, if it's not there already. You only need to be logged in to My developerWorks.

And what's the point of adding your interests to your profile? That's how you find other users with the same interests as yours, and see what they're reading and contributing to the community. Your interests also help us recommend relevant developerWorks content to you.

View your My developerWorks profile

Return from help

Help: Remove from My dW interests

What's this?

Removing this interest does not alter your profile, but rather removes this piece of content from a list of all content for which you've indicated interest. In a future enhancement to My developerWorks, you'll be able to see a record of that content.

View your My developerWorks profile

Return from help

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=XML
ArticleID=192289
ArticleTitle=XForms as an RSS reader/editor
publish-date=01302007
author1-email=ibmquestions@nicholaschase.com
author1-email-cc=dwxed@us.ibm.com

Tags

Help
Use the search field to find all types of content in My developerWorks with that tag.

Use the slider bar to see more or fewer tags.

For articles in technology zones (such as Java technology, Linux, Open source, XML), Popular tags shows the top tags for all technology zones. For articles in product zones (such as Info Mgmt, Rational, WebSphere), Popular tags shows the top tags for just that product zone.

For articles in technology zones (such as Java technology, Linux, Open source, XML), My tags shows your tags for all technology zones. For articles in product zones (such as Info Mgmt, Rational, WebSphere), My tags shows your tags for just that product zone.

Use the search field to find all types of content in My developerWorks with that tag. Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere). My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).

Try IBM PureSystems. No charge.

Special offers