This example is to demonstrate how to modify a XML document. The Slashdot RSS feed is projected to this interface and the stories will be accessible via a subprojection. This time there is a setter for a collection of Stories which will replace the existing sequence of rss items. Instead of just setting an elements value like in the last example, we now change a sequence of elements. Notice that there are name spaces in the source XML document and that we work with them intuitively.
public interface SlashdotRSSFeed { /** * We like to access each story as a java object, so we define a sub * projection here. Notice that this does not have to be an inner interface, * thats just to compact this tutorial. */ interface Story { @XBRead ( "child::title" ) String getTitle(); @XBRead ( "child::pubDate" ) String getDate(); @XBRead ( "child::description" ) String getDescription(); } /** * Our getter method with an XPath expression to select all RSS items. The * target type definition specifies this getter as returning a list of sub * projections. * * @return List of all stories */ @XBRead ( "/rss/channel/item" ) List<Story> getAllItems(); /** * Our setter uses exact the same XPath expression as the getter. Thus it * will replace the items returned by getAllItems(). Notice that it will * only replace XML elements named "item", because that is exactly what the * XPath is selecting. Other child elements of the channel element won't be * touched. * * Notice that we could define another setter which could project a story to * other elements than "item" in the document hierarchy. * * @param items */ @XBWrite ( "/rss/channel/item" ) void setAllItems(Collection<Story> items); @XBRead ( "count(/rss/channel/item)" ) int getItemCount(); /** * This is not part of this lesson about modifying documents. Just to * demonstrate the flexibility of projections. There is no need to strictly * keep the object oriented way to the stories. We just define a getter for * all creator elements of all stories without a sub projection. * * Notice the seamless use of the namespace. The projector will use the * namespaces declared in the document. * * @return A list of all creators in this feed. */ @XBRead ( "//dc:creator" ) List<String> getCreators(); /** * Another getter not part of this lesson. This time we let the projection * declaration do some filtering. Usually you would have to code this in * java. * * @return A list of open source stories. */ @XBRead ( "/rss/channel/item[dc:subject=opensource]" ) List<Story> getOpenSourceStories(); } |
And here some unit tests to print out some data about our RSS feed.
~~ This example is to demonstrate how to modify a XML document. The Slashdot RSS feed is projected to this interface and the stories will be accessible via a subprojection. This time there is a setter for a collection of Stories which will replace the existing sequence of rss items. Instead of just setting an elements value like in the last example, we now change a sequence of elements. Notice that there are name spaces in the source XML document and that we work with them intuitively. public class TestFilterRSSFeed extends TutorialTestCase{ private static SlashdotRSSFeed feed; @BeforeClass public static void readFeed() throws IOException { // XBProjector projector = new XBProjector(); // feed = projector.io().fromURLAnnotation(SlashdotRSSFeed.class); } @Ignore public void printSomeStats() { Set<String> creators = new HashSet<String>(feed.getCreators()); System.out.println( "There are " + feed.getAllItems().size() + " stories by " + creators.size() + " different creators." ); } /** * Remove all but the first three stories from a Slashdot RSS feed. Result * is formatted by standard Transformer capabilities. */ @Ignore //Slashdot changed the rss format recently. TODO: Need to think about a different examle. public void filterSomeArticles() throws IOException { List<Story> filteredItems = new LinkedList<Story>(); for (Story item : feed.getAllItems()) { filteredItems.add(item); if (filteredItems.size() == 3 ) { break ; } } // This call removes all but the given items. Other child elements stay // untouched. feed.setAllItems(filteredItems); assertEquals( 3 ,feed.getItemCount()); // System.out.println(feed.toString()); } } |