RSS Feed Tutorial


One of the most common uses of the WebParser measure in Rainmeter is to create a skin to parse and display information from an RSS or Atom feed.

This guide is not intended as a general purpose tutorial for the WebParser measure, nor does it attempt to explore all that regular expressions can do. A great deal of additional help is available at Regular Expression Options.

RSS and Atom feeds follow certain patterns that make them fairly easy to parse. While there are differences between the RSS and Atom standards, which we will touch on a bit later, let's use a simple RSS output to outline how they are laid out.

<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
<channel>
<title>RSS Title</title>
<description>This is an example of an RSS feed</description>
<link>https://www.someexamplerssdomain.com/main.html</link>
<lastBuildDate>Mon, 06 Sep 2009 16:45:00 +0000 </lastBuildDate>

<item>
<title>Example entry</title>
<description>Here is some text containing an interesting description.</description>
<link>https://www.wikipedia.org/</link>
<pubDate>Mon, 06 Sep 2009 16:45:00 +0000 </pubDate>
</item>
</channel>
</rss>

As you can see, the pattern is that there is a header section which contains "tags" for the title, description, link and lastBuildDate of the overall feed. This is followed by a series of one or more item entries, each of which has its own set of title/description/link/pubDate tags. It should be noted that there can be MANY other tags in a feed. However, in an RSS feed, the ones we are going to look at are the ones that are certain to be there, and will have the information we want for a simple RSS skin.

Sample RSS feed

What we want to do is take some representative example of an RSS feed, and get that header title, link and last build date information, then a few "items", with their title, link and publication dates. Then we will build a simple skin to display our results.

For our example of an RSS feed, let's use the feed from the site https://www.bbc.co.uk/news/. The RSS feed is found at the URL https://feeds.bbci.co.uk/news/rss.xml. If we go to that URL in our web browser, we get HTML output that looks like this:

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet title="XSL_formatting" type="text/xsl" href="/shared/bsp/xsl/rss/nolsol.xsl"?>
<rss xmlns:media="http://search.yahoo.com/mrss/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0">
<channel>
<title>BBC News - Home</title>
<link>https://feeds.bbci.co.uk/news/rss.xml</link>
<description>The latest stories from the Home section of the BBC News web site.</description>
<language>en-gb</language>
<lastBuildDate>Wed, 13 Nov 2013 14:26:44 GMT</lastBuildDate>
<copyright>Copyright: (C) British Broadcasting Corporation, see http://news.bbc.co.uk/2/hi/help/rss/4498287.stm for terms and conditions of reuse.</copyright>
<image>
<url>http://news.bbcimg.co.uk/nol/shared/img/bbc_news_120x60.gif</url>
<title>BBC News - Home</title>
<link>http://www.bbc.co.uk/news/#sa-ns_mchannel=rss&amp;ns_source=PublicRSS20-sa</link>
<width>120</width>
<height>60</height>
</image>
<ttl>15</ttl>
<atom:link href="http://feeds.bbci.co.uk/news/rss.xml" rel="self" type="application/rss+xml"/>
<item>
<title>UK recovery takes hold, says Bank</title>
<description>The UK economy will grow faster and unemployment will fall sooner than expected, says the Bank of England governor Mark Carney.</description>
<link>http://www.bbc.co.uk/news/business-24926512#sa-ns_mchannel=rss&amp;ns_source=PublicRSS20-sa</link>
<guid isPermaLink="false">http://www.bbc.co.uk/news/business-24926512</guid>
<pubDate>Wed, 13 Nov 2013 12:46:25 GMT</pubDate>
<media:thumbnail width="66" height="49" url="http://news.bbcimg.co.uk/media/images/71085000/jpg/_71085923_ze18nb50.jpg"/>
<media:thumbnail width="144" height="81" url="http://news.bbcimg.co.uk/media/images/71085000/jpg/_71085924_ze18nb50.jpg"/>
</item>
<item>
<title>UK jobless rate at three-year low</title>
<description>The UK jobless rate falls to 7.6% as the number of unemployed dropped by 48,000 to 2.47 million between July and September, say official figures</description>
<link>http://www.bbc.co.uk/news/business-24923951#sa-ns_mchannel=rss&amp;ns_source=PublicRSS20-sa</link>
<guid isPermaLink="false">http://www.bbc.co.uk/news/business-24923951</guid>
<pubDate>Wed, 13 Nov 2013 12:11:15 GMT</pubDate>
<media:thumbnail width="66" height="49" url="http://news.bbcimg.co.uk/media/images/71083000/jpg/_71083215_hi019661326.jpg"/>
<media:thumbnail width="144" height="81" url="http://news.bbcimg.co.uk/media/images/71083000/jpg/_71083216_hi019661326.jpg"/>
</item>
<item>
<title>Minister attacks starved boy review</title>
<description>Children's Minister Edward Timpson strongly criticises a report that says a four-year-old Bradford boy starved to death after being let down by "national systems".</description>
<link>http://www.bbc.co.uk/news/uk-england-24925704#sa-ns_mchannel=rss&amp;ns_source=PublicRSS20-sa</link>
<guid isPermaLink="false">http://www.bbc.co.uk/news/uk-england-24925704</guid>
<pubDate>Wed, 13 Nov 2013 12:45:06 GMT</pubDate>
<media:thumbnail width="66" height="49" url="http://news.bbcimg.co.uk/media/images/71085000/jpg/_71085461_hamzahrossparry.jpg"/>
<media:thumbnail width="144" height="81" url="http://news.bbcimg.co.uk/media/images/71085000/jpg/_71085462_hamzahrossparry.jpg"/>
</item>
<item>
<title>Philippines defends storm response</title>
<description>The Philippine government says it is facing its biggest ever logistical challenge after Typhoon Haiyan which has affected up to 11 million people.</description>
<link>http://www.bbc.co.uk/news/world-asia-24928138#sa-ns_mchannel=rss&amp;ns_source=PublicRSS20-sa</link>
<guid isPermaLink="false">http://www.bbc.co.uk/news/world-asia-24928138</guid>
<pubDate>Wed, 13 Nov 2013 13:30:28 GMT</pubDate>
<media:thumbnail width="66" height="49" url="http://news.bbcimg.co.uk/media/images/71089000/jpg/_71089597_dbd99b60-0308-451e-b9f7-5b37a0e2cc29.jpg"/>
<media:thumbnail width="144" height="81" url="http://news.bbcimg.co.uk/media/images/71089000/jpg/_71089598_dbd99b60-0308-451e-b9f7-5b37a0e2cc29.jpg"/>
</item>
<item>
<title>UK's Philippines appeal raises £13m</title>
<description>An appeal by UK charities to help victims of the Philippines typhoon raises £13m within a day of its launch.</description>
<link>http://www.bbc.co.uk/news/uk-24928593#sa-ns_mchannel=rss&amp;ns_source=PublicRSS20-sa</link>
<guid isPermaLink="false">http://www.bbc.co.uk/news/uk-24928593</guid>
<pubDate>Wed, 13 Nov 2013 13:58:47 GMT</pubDate>
<media:thumbnail width="66" height="49" url="http://news.bbcimg.co.uk/media/images/71091000/jpg/_71091064_dx1fh5vl.jpg"/>
<media:thumbnail width="144" height="81" url="http://news.bbcimg.co.uk/media/images/71091000/jpg/_71091105_dx1fh5vl.jpg"/>
</item>
<item>
<title>MI6 spy death 'probably an accident'</title>
<description>Police investigating the death of MI6 spy Gareth Williams, whose body was found in a padlocked sports bag, say it was "probably an accident".</description>
<link>http://www.bbc.co.uk/news/uk-24927078#sa-ns_mchannel=rss&amp;ns_source=PublicRSS20-sa</link>
<guid isPermaLink="false">http://www.bbc.co.uk/news/uk-24927078</guid>
<pubDate>Wed, 13 Nov 2013 13:36:31 GMT</pubDate>
<media:thumbnail width="66" height="49" url="http://news.bbcimg.co.uk/media/images/71087000/jpg/_71087088_010051215-1.jpg"/>
<media:thumbnail width="144" height="81" url="http://news.bbcimg.co.uk/media/images/71087000/jpg/_71087089_010051215-1.jpg"/>
</item>
<item>
<title>Morsi warns of Egypt instability</title>
<description>Egypt's ousted President Mohammed Morsi warns in a statement that the country will not "regain stability" until "the military coup is eliminated".</description>
<link>http://www.bbc.co.uk/news/world-middle-east-24927100#sa-ns_mchannel=rss&amp;ns_source=PublicRSS20-sa</link>
<guid isPermaLink="false">http://www.bbc.co.uk/news/world-middle-east-24927100</guid>
<pubDate>Wed, 13 Nov 2013 14:16:42 GMT</pubDate>
<media:thumbnail width="66" height="49" url="http://news.bbcimg.co.uk/media/images/71091000/jpg/_71091474_71088474.jpg"/>
<media:thumbnail width="144" height="81" url="http://news.bbcimg.co.uk/media/images/71091000/jpg/_71091475_71088474.jpg"/>
</item>
<item>
<title>NHS shake-up proposes two-tier A&amp;E</title>
<description>A two-tier A&amp;E system in England should be created as part of an overhaul of services, NHS chiefs are proposing.</description>
<link>http://www.bbc.co.uk/news/health-24914385#sa-ns_mchannel=rss&amp;ns_source=PublicRSS20-sa</link>
<guid isPermaLink="false">http://www.bbc.co.uk/news/health-24914385</guid>
<pubDate>Wed, 13 Nov 2013 08:04:23 GMT</pubDate>
<media:thumbnail width="66" height="49" url="http://news.bbcimg.co.uk/media/images/71068000/jpg/_71068405_waiting.jpg"/>
<media:thumbnail width="144" height="81" url="http://news.bbcimg.co.uk/media/images/71068000/jpg/_71068406_waiting.jpg"/>
</item>
<item>
<title>Winter fuel payments to EU double</title>
<description>The amount spent by the UK on winter fuel payments for people living in mainland Europe has almost doubled in a single year, government figures show.</description>
<link>http://www.bbc.co.uk/news/uk-politics-24924228#sa-ns_mchannel=rss&amp;ns_source=PublicRSS20-sa</link>
<guid isPermaLink="false">http://www.bbc.co.uk/news/uk-politics-24924228</guid>
<pubDate>Wed, 13 Nov 2013 13:28:08 GMT</pubDate>
<media:thumbnail width="66" height="49" url="http://news.bbcimg.co.uk/media/images/71086000/jpg/_71086428_83593896.jpg"/>
<media:thumbnail width="144" height="81" url="http://news.bbcimg.co.uk/media/images/71086000/jpg/_71086429_83593896.jpg"/>
</item>
<item>
<title>Best 'encouraged NoW intrusion'</title>
<description>Reality TV personality Calum Best was paid thousands of pounds by the News of the World for articles about his father's death, the Old Bailey hears.</description>
<link>http://www.bbc.co.uk/news/uk-24927890#sa-ns_mchannel=rss&amp;ns_source=PublicRSS20-sa</link>
<guid isPermaLink="false">http://www.bbc.co.uk/news/uk-24927890</guid>
<pubDate>Wed, 13 Nov 2013 14:24:00 GMT</pubDate>
<media:thumbnail width="66" height="49" url="http://news.bbcimg.co.uk/media/images/71089000/jpg/_71089780_71088480.jpg"/>
<media:thumbnail width="144" height="81" url="http://news.bbcimg.co.uk/media/images/71089000/jpg/_71089781_71088480.jpg"/>
</item>
<item>
<title>Energy bill hikes 'to last 17 years'</title>
<description>Consumers face 17 more years of above-inflation increases in energy and water bills, Whitehall's spending watchdog warns.</description>
<link>http://www.bbc.co.uk/news/uk-politics-24920026#sa-ns_mchannel=rss&amp;ns_source=PublicRSS20-sa</link>
<guid isPermaLink="false">http://www.bbc.co.uk/news/uk-politics-24920026</guid>
<pubDate>Wed, 13 Nov 2013 09:06:15 GMT</pubDate>
<media:thumbnail width="66" height="49" url="http://news.bbcimg.co.uk/media/images/71077000/jpg/_71077253_129544287.jpg"/>
<media:thumbnail width="144" height="81" url="http://news.bbcimg.co.uk/media/images/71077000/jpg/_71077254_129544287.jpg"/>
</item>
<item>
<title>Afghan opium harvest at record high</title>
<description>Afghan opium cultivation reaches a record level, with more than 200,000 hectares planted with the poppy for the first time, a UN report says.</description>
<link>http://www.bbc.co.uk/news/world-asia-24919056#sa-ns_mchannel=rss&amp;ns_source=PublicRSS20-sa</link>
<guid isPermaLink="false">http://www.bbc.co.uk/news/world-asia-24919056</guid>
<pubDate>Wed, 13 Nov 2013 07:41:48 GMT</pubDate>
<media:thumbnail width="66" height="49" url="http://news.bbcimg.co.uk/media/images/71074000/jpg/_71074648_64255531.jpg"/>
<media:thumbnail width="144" height="81" url="http://news.bbcimg.co.uk/media/images/71074000/jpg/_71074649_64255531.jpg"/>
</item>
<item>
<title>British drugs smuggler faces death</title>
<description>A British woman is facing the death penalty after admitting trafficking 1.4kg (3lb) of crystal methamphetamine into Indonesia.</description>
<link>http://www.bbc.co.uk/news/uk-england-24925766#sa-ns_mchannel=rss&amp;ns_source=PublicRSS20-sa</link>
<guid isPermaLink="false">http://www.bbc.co.uk/news/uk-england-24925766</guid>
<pubDate>Wed, 13 Nov 2013 14:12:22 GMT</pubDate>
<media:thumbnail width="66" height="49" url="http://news.bbcimg.co.uk/media/images/71088000/jpg/_71088589_71087334.jpg"/>
<media:thumbnail width="144" height="81" url="http://news.bbcimg.co.uk/media/images/71088000/jpg/_71088590_71087334.jpg"/>
</item>
<item>
<title>Fourth cyclist killed in eight days</title>
<description>A cyclist is killed in a crash with a lorry in east London - the fourth to die on the capital's roads in eight days.</description>
<link>http://www.bbc.co.uk/news/uk-england-london-24925390#sa-ns_mchannel=rss&amp;ns_source=PublicRSS20-sa</link>
<guid isPermaLink="false">http://www.bbc.co.uk/news/uk-england-london-24925390</guid>
<pubDate>Wed, 13 Nov 2013 13:42:05 GMT</pubDate>
<media:thumbnail width="66" height="49" url="http://news.bbcimg.co.uk/media/images/71085000/jpg/_71085485_bc6f509a-e39d-4088-8b57-9a280985b55d.jpg"/>
<media:thumbnail width="144" height="81" url="http://news.bbcimg.co.uk/media/images/71085000/jpg/_71085486_bc6f509a-e39d-4088-8b57-9a280985b55d.jpg"/>
</item>
<item>
<title>Strictly star Natalie 'fit to dance'</title>
<description>Strictly Come Dancing contestant Natalie Gumede confirms she will be dancing on Saturday's show after falling ill last week.</description>
<link>http://www.bbc.co.uk/news/entertainment-arts-24923918#sa-ns_mchannel=rss&amp;ns_source=PublicRSS20-sa</link>
<guid isPermaLink="false">http://www.bbc.co.uk/news/entertainment-arts-24923918</guid>
<pubDate>Wed, 13 Nov 2013 09:38:52 GMT</pubDate>
<media:thumbnail width="66" height="49" url="http://news.bbcimg.co.uk/media/images/71083000/jpg/_71083595_srlvarma.jpg"/>
<media:thumbnail width="144" height="81" url="http://news.bbcimg.co.uk/media/images/71083000/jpg/_71083596_srlvarma.jpg"/>
</item>
<item>
<title>Olympian Stanning back from Helmand</title>
<description>Olympic gold medallist Heather Stanning has taken part in a homecoming parade after finishing a six-month tour of Afghanistan.</description>
<link>http://www.bbc.co.uk/news/uk-24927885#sa-ns_mchannel=rss&amp;ns_source=PublicRSS20-sa</link>
<guid isPermaLink="false">http://www.bbc.co.uk/news/uk-24927885</guid>
<pubDate>Wed, 13 Nov 2013 12:31:52 GMT</pubDate>
<media:thumbnail width="66" height="49" url="http://news.bbcimg.co.uk/media/images/71087000/jpg/_71087611_71087604.jpg"/>
<media:thumbnail width="144" height="81" url="http://news.bbcimg.co.uk/media/images/71088000/jpg/_71088456_71087604.jpg"/>
</item>
</channel>
</rss>

Since a feed is meant to be read by a computer program that will parse the data from the XML / HTML output, there is often no attempt made to have the text be particularly formatted or easy to read. Sometimes a feed in your browser WILL have some HTML formatting codes to make it easier to view. If it does, you should right click and use "view page source" (or some variant of that depending on your browser), so you are looking at the raw HTML output and not formatted data.

If we look through this output, we can spot the patterns of XML "tags" that we described above.

We have the title of the feed in
<title>BBC News - Home</title>
a link to the feed in
<link>https://feeds.bbci.co.uk/news/rss.xml</link>
and the date the feed was last updated in
<lastBuildDate>Wed, 13 Nov 2013 14:26:44 GMT</lastBuildDate>.

We can then see the first of our <item> tags

This is followed by a title of
<title>UK recovery takes hold, says Bank</title>
a link of
<link>http://www.bbc.co.uk/news/business-24926512#sa-ns_mchannel=rss&ns_source=PublicRSS20-sa</link>
and a bit later on, a publication date of
<pubDate>Wed, 13 Nov 2013 12:46:25 GMT</pubDate>.

We know when we are done with any given item when we see the </item> tag.

This is followed by more <item> tags, each with their own titles, links and publication dates.

Building our skin

First, let's get the skin started.

[Rainmeter]
Update=1000
DynamicWindowSize=1

Now we will start building our first WebParser measure.

[MeasureSite]
Measure=WebParser
URL=https://feeds.bbci.co.uk/news/rss.xml

The next thing we will need is the all-important RegExp option. Again, this guide is not a tutorial for the WebParser measure, nor a tutorial for Regular Expressions. However, at a high level what we want to do is use a regular expression in the "parent measure" to search the feed and capture parts of it into StringIndex numbers that we will use later in "child measures".

We can begin by getting the title of the feed into a StringIndex.

[MeasureSite]
Measure=WebParser
URL=https://feeds.bbci.co.uk/news/rss.xml
RegExp=(?siU)<title>(.*)</title>

So we are searching for <title>, capturing () any number of characters of any kind .* into StringIndex number 1, and ending the capture when the text </title> is found.

Let's extend that RegExp option and get the link for the site and the last build date into StringIndex numbers 2 and 3.

RegExp=(?siU)<title>(.*)</title>.*<link>(.*)</link>.*<lastBuildDate>(.*)</lastBuildDate>

Notice that we use .* without parentheses to "skip" any number of any characters, without capturing anything.

So now we have those three bits of information we parsed into StringIndex numbers 1, 2 and 3. We can build some child WebParser measures to contain each of those values, that we can then use in meters.

[MeasureSite]
Measure=WebParser
URL=https://feeds.bbci.co.uk/news/rss.xml
RegExp=(?siU)<title>(.*)</title>.*<link>(.*)</link>.*<lastBuildDate>(.*)</lastBuildDate>

[MeasureSiteTitle]
Measure=WebParser
URL=[MeasureSite]
StringIndex=1

[MeasureSiteLink]
Measure=WebParser
URL=[MeasureSite]
StringIndex=2

[MeasureSiteBuildDate]
Measure=WebParser
URL=[MeasureSite]
StringIndex=3

[MeterSiteTitle]
Meter=String
MeasureName=MeasureSiteTitle
LeftMouseUpAction=["[MeasureSiteLink]"]
DynamicVariables=1

Getting the first feed item

Now that we have retrieved the site header information into our first three StringIndex numbers, let's get the first of the items from the feed. We do that by again extending our RegExp option.

[MeasureSite]
Measure=WebParser
URL=https://feeds.bbci.co.uk/news/rss.xml
RegExp=(?siU)<title>(.*)</title>.*<link>(.*)</link>.*<lastBuildDate>(.*)</lastBuildDate>.*<item>.*<title>(.*)</title>.*<link>(.*)</link>.*<pubDate>(.*)</pubdate>

The added parsing code will skip to the first <item>, then find the <title>, <link> and <pubDate>. It will put them in StringIndex numbers 4, 5 and 6. Just count the instances of (.*) in the expression to determine which StringIndex numbers contain each value.

Following the same pattern as above, we can add new child measures to reference these StringIndex numbers.

[MeasureItem1Title]
Measure=WebParser
URL=[MeasureSite]
StringIndex=4

[MeasureItem1Link]
Measure=WebParser
URL=[MeasureSite]
StringIndex=5

[MeasureItem1Date]
Measure=WebParser
URL=[MeasureSite]
StringIndex=6

Adding more feed items

Adding another item is as simple as extending our RegExp option to get the next <item> into the next three StringIndex numbers.

RegExp=(?siU)<title>(.*)</title>.*<link>(.*)</link>.*<lastBuildDate>(.*)</lastBuildDate>.*<item>.*<title>(.*)</title>.*<link>(.*)</link>.*<pubDate>(.*)</pubdate>.*<item>.*<title>(.*)</title>.*<link>(.*)</link>.*<pubDate>(.*)</pubdate>

And create some more child WebParser measures for those values.

[MeasureItem2Title]
Measure=WebParser
URL=[MeasureSite]
StringIndex=7

[MeasureItem2Link]
Measure=WebParser
URL=[MeasureSite]
StringIndex=8

[MeasureItem2Date]
Measure=WebParser
URL=[MeasureSite]
StringIndex=9

Adding a third item is just more of the same.

RegExp=(?siU)<title>(.*)</title>.*<link>(.*)</link>.*<lastBuildDate>(.*)</lastBuildDate>.*<item>.*<title>(.*)</title>.*<link>(.*)</link>.*<pubDate>(.*)</pubdate>.*<item>.*<title>(.*)</title>.*<link>(.*)</link>.*<pubDate>(.*)</pubdate>.*<item>.*<title>(.*)</title>.*<link>(.*)</link>.*<pubDate>(.*)</pubdate>

That RegExp is getting pretty long...

If you are retrieving a number of items, let's say five for instance, that RegExp is going to get pretty long and a bit hard to debug. Let's use a little trick with a variable to simplify it a bit. Go back up to the top of your skin right under the [Rainmeter] section, and create a new [Variables] section.

[Rainmeter]
Update=1000
DynamicWindowSize=1

[Variables]
Item=.*<item>.*<title>(.*)</title>.*<link>(.*)</link>.*<pubDate>(.*)</pubdate>

And change our RegExp option in our parent measure to use that new variable.

[MeasureSite]
Measure=WebParser
URL=https://feeds.bbci.co.uk/news/rss.xml
RegExp=(?siU)<title>(.*)</title>.*<link>(.*)</link>.*<lastBuildDate>(.*)</lastBuildDate>#Item#

Since the variable #Item# is replaced in the RegExp with .*<item>.*<title>(.*)</title>.*<link>(.*)</link>.*<pubDate>(.*)</pubdate>, we still get our parse of the site header information into StringIndex numbers 1, 2 and 3, and our first <item> into StringIndex numbers 4, 5 and 6. However the RegExp is quite a bit shorter and easier to read and debug. Adding more items is as simple as repeating that variable.

RegExp=(?siU)<title>(.*)</title>.*<link>(.*)</link>.*<lastBuildDate>(.*)</lastBuildDate>#Item##Item##Item##Item##Item#

That will get a total of five items, with the total of StrinIndex numbers at 18. Now you just create all the child measures you need to pick off those 18 values, and display them as you like in meters.

A few more advanced suggestions

DecodeCharacterReference

An RSS or Atom feed can contain the HTML codes for some characters, ones that you would want to display as the actual character instead of the code. For instance, the raw data might contain the code &lt; which is the < character. You don't want to dislay the code, but the actual <.

If you add the option DecodeCharacterReference=1 to any or all desired child measures, Rainmeter will translate and display the correct character for the embedded HTML code.

[MeasureItem1Title]
Measure=WebParser
URL=[MeasureSite]
StringIndex=4
DecodeCharacterReference=1

Generally, you will need this only on the "title" child measures, as the "link" and "pubdate" entries will almost never contain any of these HTML codes.

Substitute

One of the other things you will run into in feeds, more often in Atom feeds than in RSS, is the <![CDATA[ ]]> tag around some data. It will take the form <![CDATA[Some Text in here]]>. This special tag construct in HTML just means that any text inside the opening <![CDATA[ and the closing ]]> will be displayed as the characters, without any problems with characters that are illegal in XML data. (like &, <, > " and others)

While it would be complicated and annoying to use your regular expression to "parse around" this tag, you certainly don't want that text displayed as part of your skin output. You can use the Substitute option to find and remove this text on any or all child measures. Note that sometime the feed will start and end the tag with < and > and sometimes not. We should use Substitute to take care of both cases.

[MeasureItem1Title]
Measure=WebParser
URL=[MeasureSite]
StringIndex=4
DecodeCharacterReference=1
Substitute="<![CDATA[":"","]]>":"","![CDATA[":"","]]":""

Regular Expression Substitute

Sometimes a feed will be formatted in such a way that there are leading spaces or tabs in front of a value. An example would be:

<item>
<title>
This is an item title
</title>
</item>

We don't want to capture and display those leading tab characters in this example, so we can use the RegExpSubstitute option instead of the normal Substitute, so we can take advantage of the additional power of regular expressions in our substitution.

[MeasureItem1Title]
Measure=WebParser
URL=[MeasureSite]
StringIndex=4
DecodeCharacterReference=1
RegExpSubstitute=1
Substitute="^\s+":"","<!\[CDATA\[":"","\]\]>":"","!\[CDATA\[":"","\]\]":""

We are using the regular expression construct at the beginning to say "if the start of the string ^ contains one or more "white space" characters \s+, then change them to empty strings "".

Note that since the [ and ] characters are "reserved" in regular expressions, we needed to "escape" them using the \ character in our Substitute when we use RegExpSubstitute.

Lookahead Assertions

In our example above, we used our #Item# variable in our RegExp option to retrieve five "items" from the feed. What if there are currently only four items in the feed? Our regular expression will fail, and no information at all will be obtained.

You can protect against this by using what is known in regular expressions as a "lookahead assertion". What this does is basically say "if the following text exists, then parse it this way. If not, then just skip that part of the regular expression without failing". The format for using a lookahead assertion in regular expressions looks a bit daunting, but in concept it is not too hard to wrap your head around. I strongly suggest looking at the guide at WebParser - Lookahead Assertions.

To cut to the chase, if we change our #Item# variable to this:

[Variables]
Item=(?(?=.*<item>).*<item>.*<title>(.*)</title>.*<link>(.*)</link>.*<pubDate>(.*)</pubDate>)

Then we are saying "look ahead" (? for a string that equals (?= .*<item>)" Note the trailing parentheses to end the "look for" part of the expression. If the string .*<item> is found, then execute the the parse .*<item>.*<title>(.*)</title>.*<link>(.*)</link>.*<pubDate>(.*)</pubDate>. Note that then we follow the entire thing with another ending parentheses, to end the "look ahead" part of the expression.

If the lookahead assertion fails, only that part contained in it will be ignored, and any other parts of the expression will still be evaluated and return data.

Putting it all together

Here is a full skin, using all we have learned so far, that will parse and display the first five items from our RSS feed site. You can copy this code and paste it into a new skin to test it out, modify the output meters as and if you like, and you are well on your way!

[Rainmeter]
Update=1000
DynamicWindowSize=1

[Variables]
Item=(?(?=.*<item>).*<item>.*<title>(.*)</title>.*<link>(.*)</link>.*<pubDate>(.*)</pubDate>)
Sub="^\s+":"","<!\[CDATA\[":"","\]\]>":"","!\[CDATA\[":"","\]\]":""

[MeasureSite]
Measure=WebParser
URL=https://feeds.bbci.co.uk/news/rss.xml
RegExp=(?siU)<title>(.*)</title>.*<link>(.*)</link>.*<lastBuildDate>(.*)</lastBuildDate>#Item##Item##Item##Item##Item#

;Site info

[MeasureSiteTitle]
Measure=WebParser
URL=[MeasureSite]
StringIndex=1
DecodeCharacterReference=1
RegExpSubstitute=1
Substitute=#Sub#

[MeasureSiteLink]
Measure=WebParser
URL=[MeasureSite]
StringIndex=2

[MeasureSiteDate]
Measure=WebParser
URL=[MeasureSite]
StringIndex=3

;Item 1 info

[MeasureItem1Title]
Measure=WebParser
URL=[MeasureSite]
StringIndex=4
DecodeCharacterReference=1
RegExpSubstitute=1
Substitute=#Sub#

[MeasureItem1Link]
Measure=WebParser
URL=[MeasureSite]
StringIndex=5

[MeasureItem1Date]
Measure=WebParser
URL=[MeasureSite]
StringIndex=6

;Item 2 info

[MeasureItem2Title]
Measure=WebParser
URL=[MeasureSite]
StringIndex=7
DecodeCharacterReference=1
RegExpSubstitute=1
Substitute=#Sub#

[MeasureItem2Link]
Measure=WebParser
URL=[MeasureSite]
StringIndex=8

[MeasureItem2Date]
Measure=WebParser
URL=[MeasureSite]
StringIndex=9

;Item 3 info

[MeasureItem3Title]
Measure=WebParser
URL=[MeasureSite]
StringIndex=10
DecodeCharacterReference=1
RegExpSubstitute=1
Substitute=#Sub#

[MeasureItem3Link]
Measure=WebParser
URL=[MeasureSite]
StringIndex=11

[MeasureItem3Date]
Measure=WebParser
URL=[MeasureSite]
StringIndex=12

;Item 4 info

[MeasureItem4Title]
Measure=WebParser
URL=[MeasureSite]
StringIndex=13
DecodeCharacterReference=1
RegExpSubstitute=1
Substitute=#Sub#

[MeasureItem4Link]
Measure=WebParser
URL=[MeasureSite]
StringIndex=14

[MeasureItem4Date]
Measure=WebParser
URL=[MeasureSite]
StringIndex=15

;Item 5 info

[MeasureItem5Title]
Measure=WebParser
URL=[MeasureSite]
StringIndex=16
DecodeCharacterReference=1
RegExpSubstitute=1
Substitute=#Sub#

[MeasureItem5Link]
Measure=WebParser
URL=[MeasureSite]
StringIndex=17

[MeasureItem5Date]
Measure=WebParser
URL=[MeasureSite]
StringIndex=18

;MeterStyles

[TextStyle]
X=5
Y=3R
W=290
H=40
FontFace=Segoe UI
FontSize=11
FontColor=255,255,255,255
SolidColor=0,0,0,1
ClipString=1
AntiAlias=1
ToolTipWidth=300

;Meters

[MeterBackground]
Meter=Image
W=300
H=255
SolidColor=50,50,50,255

[MeterSite]
Meter=String
MeasureName=MeasureSiteTitle
MeterStyle=TextStyle
H=20
Y=5
FontColor=196,245,184,255
StringStyle=Bold
LeftMouseUpAction=["[MeasureSiteLink]"]
ToolTipText=%1#CRLF#[MeasureSiteDate]
DynamicVariables=1

[MeterItem1]
Meter=String
MeasureName=MeasureItem1Title
MeterStyle=TextStyle
Y=10R
LeftMouseUpAction=["[MeasureItem1Link]"]
ToolTipText=%1#CRLF#[MeasureItem1Date]
DynamicVariables=1

[MeterItem2]
Meter=String
MeasureName=MeasureItem2Title
MeterStyle=TextStyle
LeftMouseUpAction=["[MeasureItem2Link]"]
ToolTipText=%1#CRLF#[MeasureItem2Date]
DynamicVariables=1

[MeterItem3]
Meter=String
MeasureName=MeasureItem3Title
MeterStyle=TextStyle
LeftMouseUpAction=["[MeasureItem3Link]"]
ToolTipText=%1#CRLF#[MeasureItem3Date]
DynamicVariables=1

[MeterItem4]
Meter=String
MeasureName=MeasureItem4Title
MeterStyle=TextStyle
LeftMouseUpAction=["[MeasureItem4Link]"]
ToolTipText=%1#CRLF#[MeasureItem4Date]
DynamicVariables=1

[MeterItem5]
Meter=String
MeasureName=MeasureItem5Title
MeterStyle=TextStyle
LeftMouseUpAction=["[MeasureItem5Link]"]
ToolTipText=%1#CRLF#[MeasureItem5Date]
DynamicVariables=1

Atom vs. RSS feeds

The instructions and examples above should work for virtually any RSS feed site. However, if the site you are parsing is based on the Atom feed standard, there are some differences we need to take into account. Here is a sample of an Atom feed:

<?xml version="1.0" encoding="utf-8"?>

<feed xmlns="http://www.w3.org/2005/Atom">
<title>Example Feed</title>
<subtitle>A subtitle.</subtitle>
<link href="http://example.org/feed/" rel="self" />
<link href="http://example.org/" />
<id>urn:uuid:60a76c80-d399-11d9-b91C-0003939e0af6</id>
<updated>2003-12-13T18:30:02Z</updated>

<entry>
<title>Atom-Powered Robots Run Amok</title>
<link href="http://example.org/2003/12/13/atom03" />
<link rel="alternate" type="text/html" href="http://example.org/2003/12/13/atom03.html"/>
<link rel="edit" href="http://example.org/2003/12/13/atom03/edit"/>
<id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
<updated>2003-12-13T18:30:02Z</updated>
<summary>Some text.</summary>
<author>
<name>John Doe</name>
<email>johndoe@example.com</email>
</author>
</entry>
</feed>

As you can see, there are differences in both the names of the "tags" used to identify data values, and some differences in formatting within the tags themselves.

RSS

<item>
<title>
<link>
<pubDate>

Atom

<entry>
<title type="SomeValue">
<link href="SomeSite.com"/>
<updated>

Fortunately, we can for the most part just change our RegExp to account for these differences, and the balance of what we learned making our RSS skin works just fine. It should also be noted that the order of the tags in different Atoms feeds can vary, where RSS feeds generally have the tags always in the same order. This may mean some re-ordering of the StringIndex numbers you use with your measures.

Here is an example output from the Atom feed on the Rainmeter forums:

<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en-gb">
<link rel="self" type="application/atom+xml" href="https://forum.rainmeter.net/feed.php" />

<title>Rainmeter Forums</title>
<link href="https://forum.rainmeter.net/index.php" />
<updated>2013-06-28T10:02:44-05:00</updated>

<author><name><![CDATA[Rainmeter Forums]]></name></author>
<id>http://forum.rainmeter.net/feed.php</id>
<entry>
<author><name><![CDATA[Virginityrocks]]></name></author>
<updated>2013-06-28T10:02:44-05:00</updated>
<published>2013-06-28T10:02:44-05:00</published>
<id>http://forum.rainmeter.net/viewtopic.php?p=89161#p89161</id>
<link href="https://forum.rainmeter.net/viewtopic.php?p=89161#p89161"/>
<title type="html"><![CDATA[Bugs &amp; Feature Suggestions • Re: Rainmeter in the taskbar]]></title>

<content type="html"><![CDATA[
You can pl...<p>Statistics: Posted by <a href="">Virginityrocks</a> — Fri Jun 28, 2013 10:02 am</p>]]></content>
</entry>
<entry>
<author><name><![CDATA[Virginityrocks]]></name></author>
<updated>2013-06-28T09:31:33-05:00</updated>
<published>2013-06-28T09:31:33-05:00</published>
<id>http://forum.rainmeter.net/viewtopic.php?p=89160#p89160</id>
<link href="https://forum.rainmeter.net/viewtopic.php?p=89160#p89160"/>
<title type="html"><![CDATA[Bugs &amp; Feature Suggestions • Re: Empty &quot;blank&quot; characters not showing when using UseD2D=1]]></title>

<content type="html"><![CDATA[
It's a leg...<p>Statistics: Posted by <a href="">Virginityrocks</a> — Fri Jun 28, 2013 9:31 am</p>]]></content>
</entry>
<entry>
<author><name><![CDATA[vandey]]></name></author>
<updated>2013-06-28T08:56:44-05:00</updated>
<published>2013-06-28T08:56:44-05:00</published>
<id>http://forum.rainmeter.net/viewtopic.php?p=89159#p89159</id>
<link href="https://forum.rainmeter.net/viewtopic.php?p=89159#p89159"/>
<title type="html"><![CDATA[Bugs &amp; Feature Suggestions • Feature Request: Stay on top when computer locked]]></title>

<content type="html"><![CDATA[
I have a s...<p>Statistics: Posted by <a href="">vandey</a> — Fri Jun 28, 2013 8:56 am</p>]]></content>
</entry>
<entry>
<author><name><![CDATA[moshi]]></name></author>
<updated>2013-06-28T08:40:20-05:00</updated>
<published>2013-06-28T08:40:20-05:00</published>
<id>http://forum.rainmeter.net/viewtopic.php?p=89158#p89158</id>
<link href="https://forum.rainmeter.net/viewtopic.php?p=89158#p89158"/>
<title type="html"><![CDATA[Bugs &amp; Feature Suggestions • Re: Empty &quot;blank&quot; characters not showing when using UseD2D=1]]></title>

<content type="html"><![CDATA[
i am prett...<p>Statistics: Posted by <a href="">moshi</a> — Fri Jun 28, 2013 8:40 am</p>]]></content>
</entry>
<entry>
<author><name><![CDATA[psyco]]></name></author>
<updated>2013-06-28T07:23:55-05:00</updated>
<published>2013-06-28T07:23:55-05:00</published>
<id>http://forum.rainmeter.net/viewtopic.php?p=89157#p89157</id>
<link href="https://forum.rainmeter.net/viewtopic.php?p=89157#p89157"/>
<title type="html"><![CDATA[Help: Rainmeter Skins • Re: Image ABOVE text]]></title>

<content type="html"><![CDATA[
ikarus1969...<p>Statistics: Posted by <a href="">psyco</a> — Fri Jun 28, 2013 7:23 am</p>]]></content>
</entry>
<entry>
<author><name><![CDATA[ikarus1969]]></name></author>
<updated>2013-06-28T06:18:58-05:00</updated>
<published>2013-06-28T06:18:58-05:00</published>
<id>http://forum.rainmeter.net/viewtopic.php?p=89156#p89156</id>
<link href="https://forum.rainmeter.net/viewtopic.php?p=89156#p89156"/>
<title type="html"><![CDATA[Help: Rainmeter Skins • Re: IP Location Map]]></title>

<content type="html"><![CDATA[
what about...<p>Statistics: Posted by <a href="">ikarus1969</a> — Fri Jun 28, 2013 6:18 am</p>]]></content>
</entry>
<entry>
<author><name><![CDATA[alexandeu]]></name></author>
<updated>2013-06-28T05:04:46-05:00</updated>
<published>2013-06-28T05:04:46-05:00</published>
<id>http://forum.rainmeter.net/viewtopic.php?p=89155#p89155</id>
<link href="https://forum.rainmeter.net/viewtopic.php?p=89155#p89155"/>
<title type="html"><![CDATA[General Discussion • A thank you note.]]></title>

<content type="html"><![CDATA[
As I alway...<p>Statistics: Posted by <a href="">alexandeu</a> — Fri Jun 28, 2013 5:04 am</p>]]></content>
</entry>
<entry>
<author><name><![CDATA[moshi]]></name></author>
<updated>2013-06-28T04:41:46-05:00</updated>
<published>2013-06-28T04:41:46-05:00</published>
<id>http://forum.rainmeter.net/viewtopic.php?p=89154#p89154</id>
<link href="https://forum.rainmeter.net/viewtopic.php?p=89154#p89154"/>
<title type="html"><![CDATA[Help: Rainmeter Application • Re: Email settings folder path...c:/where?]]></title>

<content type="html"><![CDATA[
Quote:Does...<p>Statistics: Posted by <a href="">moshi</a> — Fri Jun 28, 2013 4:41 am</p>]]></content>
</entry>
<entry>
<author><name><![CDATA[Frostschaden]]></name></author>
<updated>2013-06-28T03:57:11-05:00</updated>
<published>2013-06-28T03:57:11-05:00</published>
<id>http://forum.rainmeter.net/viewtopic.php?p=89153#p89153</id>
<link href="https://forum.rainmeter.net/viewtopic.php?p=89153#p89153"/>
<title type="html"><![CDATA[Help: Rainmeter Skins • Re: IP Location Map]]></title>

<content type="html"><![CDATA[
The soluti...<p>Statistics: Posted by <a href="">Frostschaden</a> — Fri Jun 28, 2013 3:57 am</p>]]></content>
</entry>
<entry>
<author><name><![CDATA[ikarus1969]]></name></author>
<updated>2013-06-28T03:37:52-05:00</updated>
<published>2013-06-28T03:37:52-05:00</published>
<id>http://forum.rainmeter.net/viewtopic.php?p=89152#p89152</id>
<link href="https://forum.rainmeter.net/viewtopic.php?p=89152#p89152"/>
<title type="html"><![CDATA[Help: Rainmeter Skins • Re: Image ABOVE text]]></title>

<content type="html"><![CDATA[
Change the...<p>Statistics: Posted by <a href="">ikarus1969</a> — Fri Jun 28, 2013 3:37 am</p>]]></content>
</entry>
</feed>

And the variable for the #Item# and the parent WebParser measure you can use to parse the same five items from this feed:

[Variables]
Item=(?(?=.*<entry>).*<entry>.*<updated>(.*)</updated>.*<link.*"(.*)".*<title.*>(.*)</title>)
Sub="^\s+":"","<!\[CDATA\[":"","\]\]>":"","!\[CDATA\[":"","\]\]":""

[MeasureSite]
Measure=WebParser
URL=https://forum.rainmeter.net/feed.php
RegExp=(?siU)<title>(.*)</title>.*<link.*"(.*)".*<updated>(.*)</updated>#Item##Item##Item##Item##Item#