/*
* Copyright (c) 1999-2002 ChurchillObjects.com All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer. Redistributions in
* binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution. Neither the name of the copyright
* holder nor the names of its contributors may be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT, INCLUDING NEGLIGENCE OR OTHERWISE, ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
*/
package churchillobjects.rss4j.parser;
import java.text.ParseException;
import java.util.Vector;
import java.util.Hashtable;
import java.util.Enumeration;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import churchillobjects.rss4j.model.IUsesDublinCore;
import churchillobjects.rss4j.model.IUsesSyndication;
import churchillobjects.rss4j.model.RssNamespace;
import churchillobjects.rss4j.model.IUsesJbnPatch;
import churchillobjects.rss4j.RssDocument;
import churchillobjects.rss4j.RssJbnDependency;
import churchillobjects.rss4j.RssJbnPatch;
import churchillobjects.rss4j.RssChannel;
import churchillobjects.rss4j.RssChannelItem;
import churchillobjects.rss4j.RssChannelTextInput;
import churchillobjects.rss4j.RssChannelImage;
import churchillobjects.rss4j.RssSyndication;
import churchillobjects.rss4j.RssDublinCore;
/**
* Class to parse an RSS document according to the specifications of the RSS
* 1.0 standard. This object is created when the base parser already started
* parsing the document (and knows what the version number is), so it is given
* the document object and the known namespaces up to that point.
*/
class RssParserImpl100 extends RssParserImpl090{
/**
* Constructor for this RSS verion's parser. Provided with an already
* set-up document and namespace.
* @param document
* @param namespaces
*/
RssParserImpl100( RssDocument document, Vector namespaces){
super(document, namespaces);
}
/**
* Canonical version number that is handled by this parser.
*/
private static final String VERSION = "1.0";
/**
* Maps resource strings to item objects.
*/
private Hashtable itemMappings = new Hashtable();
/**
* Maps resource strings to image objects.
*/
private Hashtable imageMappings = new Hashtable();
/**
* Maps resource strings to text input objects.
*/
private Hashtable textInputMappings = new Hashtable();
/**
* A list of item resource strings that have not yet been found in the
* document. In a correct RSS 1.0 document, this list will be emptied before
* the document ends.
*/
private Vector unmappedItems = new Vector();
/**
* A list of image resource strings that have not yet been found in the
* document. In a correct RSS 1.0 document, this list will be emptied before
* the document ends.
*/
private Vector unmappedImages = new Vector();
/**
* A list of text input resource strings that have not yet been found in the
* document. In a correct RSS 1.0 document, this list will be emptied before
* the document ends.
*/
private Vector unmappedTextInputs = new Vector();
/**
* Flag to indicate that channel items are being parsed.
*/
private boolean inChannelItems = false;
/**
* Flag to indicate that we are within the item sequence.
*/
private boolean inChannelItemsSeq = false;
private boolean inJbnProducts = false;
private RssJbnDependency currentJbnDependency = null;
private boolean inJbnRequires = false;
private boolean inJbnReplaces = false;
private boolean inJbnIsReplacedBy = false;
private boolean inJbnCompatibleWith = false;
private boolean inJbnAutomatedInstallation = false;
/**
* SAX event. Used to set flags for where the parser is in the document
* and to handle major parts of the RSS document object model.
* @param uri
* @param name
* @param qName
* @param attrs
*/
public void startElement(String uri, String name, String qName, Attributes attrs) throws SAXException{
try{
if("channel".equals(name)){
handleChannel(uri, name, qName, attrs);
}
if("item".equals(name) || "rdf:li".equals(qName)){
handleItem(uri, name, qName, attrs);
}
if("textinput".equals(name)){
handleTextInput(uri, name, qName, attrs);
}
if("image".equals(name)){
handleImage(uri, name, qName, attrs);
}
if("items".equals(qName) && inChannel){
inChannelItems = true;
}
if("rdf:Seq".equals(qName) && inChannel && inChannelItems){
inChannelItemsSeq = true;
}
if( (RssJbnPatch.PREFIX + ":" + RssJbnPatch.ATTR_PRODUCTS).equals( qName) ||
(RssJbnPatch.PREFIX + ":" + RssJbnPatch.ATTR_PRODUCT).equals( qName) ||
(RssJbnPatch.PREFIX + ":" + RssJbnPatch.ATTR_REQUIRES).equals( qName) ||
(RssJbnPatch.PREFIX + ":" + RssJbnPatch.ATTR_REPLACES).equals( qName) ||
(RssJbnPatch.PREFIX + ":" + RssJbnPatch.ATTR_IS_REPLACED_BY).equals( qName) ||
(RssJbnPatch.PREFIX + ":" + RssJbnPatch.ATTR_PATCH).equals( qName) ||
(RssJbnPatch.PREFIX + ":" + RssJbnPatch.ATTR_AUTOMATED_INSTALL).equals( qName) ||
(RssJbnPatch.PREFIX + ":" + RssJbnPatch.ATTR_INSTRUCTION_SET).equals( qName))
{
handleEmbeddedElement(uri, name, qName, attrs);
}
}
catch(RssParseException e){
throw new SAXException(e);
}
}
/**
* SAX event. Used to set flags for where the parser is in the document,
* and to pick up characters and set them to their elements in the RSS
* object hierarchy.
* @param uri
* @param name
* @param qName
* @throws SAXException
*/
public void endElement(String uri, String name, String qName) throws SAXException{
try{
if("channel".equals(qName)){
currentChannel = null;
inChannel = false;
}
if("item".equals(qName) && !inChannel){
currentItem = null;
inItem = false;
}
if("textinput".equals(qName) && !inChannel){
currentTextInput = null;
inTextInput = false;
}
if("image".equals(qName) && !inChannel){
currentImage = null;
inImage = false;
}
if("items".equals(qName) && inChannel){
inChannelItems = false;
}
if("rdf:Seq".equals(qName) && inChannel && inChannelItems){
inChannelItemsSeq = false;
}
if( inItem && inJbnProducts && (RssJbnPatch.PREFIX + ":" + RssJbnPatch.ATTR_PRODUCTS).equals( qName ) )
{
inJbnProducts = false;
currentJbnDependency = null;
}
if( inItem && inJbnReplaces && (RssJbnPatch.PREFIX + ":" + RssJbnPatch.ATTR_REPLACES).equals( qName ) )
{
inJbnReplaces = false;
currentJbnDependency = null;
}
if( inItem && inJbnRequires && ( RssJbnPatch.PREFIX + ":" + RssJbnPatch.ATTR_REQUIRES).equals( qName ) )
{
inJbnRequires = false;
currentJbnDependency = null;
}
if( inItem && inJbnIsReplacedBy && (RssJbnPatch.PREFIX + ":" + RssJbnPatch.ATTR_IS_REPLACED_BY).equals( qName ) )
{
inJbnIsReplacedBy = false;
currentJbnDependency = null;
}
if( inItem && inJbnCompatibleWith && (RssJbnPatch.PREFIX + ":" + RssJbnPatch.ATTR_COMPATIBLE_WITH).equals( qName ) )
{
inJbnCompatibleWith = false;
currentJbnDependency = null;
}
if( inItem && inJbnAutomatedInstallation && (RssJbnPatch.PREFIX + ":" + RssJbnPatch.ATTR_AUTOMATED_INSTALL).equals( qName ) )
{
inJbnAutomatedInstallation = false;
currentJbnDependency = null;
}
// all others are fields within others,
// if no chars then no sense in continuing
if(!hasChars()){
return;
}
if(inChannel && !(inImage || inItem || inTextInput)){
addChannelAttribute(name, qName);
}
if(inImage){
addImageAttribute(name, qName);
}
if(inItem){
addItemAttribute(name, qName);
}
if(inTextInput){
addTextInputAttribute(name, qName);
}
if( inItem &&
( inJbnProducts &&
( RssJbnPatch.PREFIX + ":" + RssJbnPatch.ATTR_PRODUCT).equals( qName ) ||
( inJbnReplaces || inJbnRequires || inJbnIsReplacedBy || inJbnCompatibleWith) &&
( RssJbnPatch.PREFIX + ":" + RssJbnPatch.ATTR_PATCH).equals( qName ) ) ||
inJbnAutomatedInstallation &&
( RssJbnPatch.PREFIX + ":" + RssJbnPatch.ATTR_INSTRUCTION_SET).equals( qName ))
{
currentJbnDependency = null;
}
resetChars();
}
catch(RssParseException e){
throw new SAXException(e);
}
}
/**
* Adds a text input attribute value from the characters buffer.
* @param name
* @param qName
*/
private void addTextInputAttribute(String name, String qName) throws RssParseException{
String value = getChars();
if("title".equals(qName)){
currentTextInput.setInputTitle(value);
}
if("description".equals(qName)){
currentTextInput.setInputDescription(value);
}
if("name".equals(qName)){
currentTextInput.setInputName(value);
}
if("link".equals(qName)){
currentTextInput.setInputLink(value);
}
if(qName.startsWith("dc:")){
handleDublinCore(currentTextInput, name, value);
}
if(qName.startsWith( RssJbnPatch.PREFIX + ":" ) ){
handleJbnPatch(currentTextInput, name, value);
}
}
/**
* Adds an item attribute value from the characters buffer.
* @param name
* @param qName
*/
private void addItemAttribute(String name, String qName) throws RssParseException{
String value = getChars();
if("title".equals(qName)){
currentItem.setItemTitle(value);
}
if("link".equals(qName)){
currentItem.setItemLink(value);
}
if("description".equals(qName)){
currentItem.setItemDescription(value);
}
if(qName.startsWith("dc:")){
handleDublinCore(currentItem, name, value);
}
if(qName.startsWith( RssJbnPatch.PREFIX + ":" )){
handleJbnPatch(currentItem, name, value);
}
}
/**
* Adds an image attribute value from the characters buffer.
* @param name
* @param qName
*/
private void addImageAttribute(String name, String qName) throws RssParseException{
String value = getChars();
if("title".equals(name)){
currentImage.setImageTitle(value);
}
if("url".equals(name)){
currentImage.setImageUrl(value);
}
if("link".equals(name)){
currentImage.setImageLink(value);
}
if(qName.startsWith("dc:")){
handleDublinCore(currentImage, name, value);
}
if(qName.startsWith( RssJbnPatch.PREFIX + ":" )){
handleJbnPatch(currentItem, name, value);
}
}
/**
* Adds a channel attribute value from the characters buffer.
* @param name
* @param qName
*/
private void addChannelAttribute(String name, String qName) throws RssParseException{
String value = getChars();
if("title".equals(qName)){
currentChannel.setChannelTitle(value);
}
if("link".equals(qName)){
currentChannel.setChannelLink(value);
}
if("description".equals(qName)){
currentChannel.setChannelDescription(value);
}
if(qName.startsWith("sy:")){
handleSyndication(currentChannel, name, value);
}
if(qName.startsWith("dc:")){
handleDublinCore(currentChannel, name, value);
}
if(qName.startsWith( RssJbnPatch.PREFIX + ":" )){
handleJbnPatch(currentItem, name, value);
}
}
/**
* SAX event. Performs a check for leftover images, items and textinputs
* that would indicate an incomplete RSS 1.0 document.
*/
public void endDocument() throws SAXException{
try{
checkForLeftovers();
}
catch(RssParseException e){
throw new SAXException(e);
}
}
/**
* Handles a channel element. Sets the current channel to a new instance and
* sets its uri from the about attribute.
* @param uri
* @param name
* @param qName
* @param attrs
*/
protected void handleChannel(String uri, String name, String qName, Attributes attrs) throws RssParseException{
currentChannel = new RssChannel();
String about = getAttributeUnqualified(name, "about", "rdf", attrs);
currentChannel.setChannelUri(about);
document.addChannel(currentChannel);
inChannel = true;
}
/**
* Handles an item and rdf:li element. Matches them together based on their
* about/resource attributes.
* @param uri
* @param name
* @param qName
* @param attrs
*/
protected void handleItem(String uri, String name, String qName, Attributes attrs) throws RssParseException{
if("item".equals(name) && !inChannel){
String about = getAttributeUnqualified(name, "about", "rdf", attrs);
currentItem = (RssChannelItem)itemMappings.get(about);
if(currentItem==null){
document.addWarning("Encountered an <item> element under <rdf:RDF> that was not used in a preceding channel: "+about);
}
else{
unmappedItems.removeElement(about);
inItem = true;
}
}
else if("rdf:li".equals(qName) && inChannel && inChannelItems && inChannelItemsSeq){
String resource = getAttributeUnqualified(qName, "resource", "rdf", attrs);
RssChannelItem item = new RssChannelItem();
currentChannel.addItem(item);
itemMappings.put(resource, item);
unmappedItems.addElement(resource);
}
}
protected void handleEmbeddedElement( String uri, String name, String qName, Attributes attrs ) throws RssParseException
{
if( (inJbnProducts &&
(RssJbnPatch.PREFIX + ":" + RssJbnPatch.ATTR_PRODUCT).equals( qName ) ) ||
(inJbnReplaces || inJbnRequires || inJbnIsReplacedBy || inJbnCompatibleWith ) &&
(RssJbnPatch.PREFIX + ":" + RssJbnPatch.ATTR_PATCH).equals( qName ) ||
inJbnAutomatedInstallation &&
(RssJbnPatch.PREFIX + ":" + RssJbnPatch.ATTR_INSTRUCTION_SET).equals( qName ))
{
currentJbnDependency = new RssJbnDependency();
currentJbnDependency.setUrl( getAttributeUnqualified( qName, "about", "rdf", attrs ) );
if( (RssJbnPatch.PREFIX + ":" + RssJbnPatch.ATTR_PRODUCT).equals( qName ) )
{
currentJbnDependency.setProductName( getAttributeUnqualified( qName, RssJbnDependency.ATTR_PRODUCT_NAME,
RssJbnPatch.PREFIX, attrs ) );
currentJbnDependency.setProductVersion( getAttributeUnqualified( qName, RssJbnDependency.ATTR_PRODUCT_VERSION,
RssJbnPatch.PREFIX, attrs ) );
currentJbnDependency.setJonResourceType( getAttributeUnqualified( qName, RssJbnDependency.ATTR_JON_RESOURCE_TYPE,
RssJbnPatch.PREFIX, attrs ) );
currentJbnDependency.setJonResourceVersion( getAttributeUnqualified( qName, RssJbnDependency.ATTR_JON_RESOURCE_VERSION,
RssJbnPatch.PREFIX, attrs ) );
}
}
else if( (RssJbnPatch.PREFIX + ":" + RssJbnPatch.ATTR_PRODUCTS).equals( qName ) )
{
inJbnProducts = true;
}
else if( (RssJbnPatch.PREFIX + ":" + RssJbnPatch.ATTR_REPLACES).equals( qName ) )
{
inJbnReplaces = true;
}
else if( (RssJbnPatch.PREFIX + ":" + RssJbnPatch.ATTR_REQUIRES).equals( qName ) )
{
inJbnRequires = true;
}
else if( (RssJbnPatch.PREFIX + ":" + RssJbnPatch.ATTR_IS_REPLACED_BY).equals( qName ) )
{
inJbnIsReplacedBy = true;
}
else if( (RssJbnPatch.PREFIX + ":" + RssJbnPatch.ATTR_COMPATIBLE_WITH).equals( qName ) )
{
inJbnCompatibleWith = true;
}
else if( (RssJbnPatch.PREFIX + ":" + RssJbnPatch.ATTR_AUTOMATED_INSTALL).equals( qName ) )
{
inJbnAutomatedInstallation = true;
}
}
/**
* Handles a new textinput element. Distinguishes between a textinput that
* occurs within a channel and one that does not. Matches them together based on their
* about/resource attributes.
* @param uri
* @param name
* @param qName
* @param attrs
*/
protected void handleTextInput(String uri, String name, String qName, Attributes attrs) throws RssParseException{
if(inChannel){
RssChannelTextInput textInput = new RssChannelTextInput();
String resource = getAttributeUnqualified(name, "resource", "rdf", attrs);
textInputMappings.put(resource, textInput);
unmappedTextInputs.addElement(resource);
currentChannel.setChannelTextInput(textInput);
}
else{
String about = getAttributeUnqualified(name, "about", "rdf", attrs);
currentTextInput = (RssChannelTextInput)textInputMappings.get(about);
if(currentTextInput==null){
document.addWarning("Encountered a <textinput> element under <rdf:RDF> that was not used in a preceding channel: "+about);
}
else{
unmappedTextInputs.removeElement(about);
inTextInput = true;
}
}
}
/**
* Handles a new image element. Distinguishes between an image that occurs
* within a channel and one that does not.
* @param uri
* @param name
* @param qName
* @param attrs
*/
protected void handleImage(String uri, String name, String qName, Attributes attrs) throws RssParseException{
if(inChannel){
// image tag within channel
RssChannelImage image = new RssChannelImage();
String resource = getAttributeUnqualified(name, "resource", "rdf", attrs);
imageMappings.put(resource, image);
unmappedImages.addElement(resource);
currentChannel.setChannelImage(image);
}
else{
// image tag outside channel
String about = getAttributeUnqualified(name, "about", "rdf", attrs);
currentImage = (RssChannelImage)imageMappings.get(about);
if(currentImage==null){
document.addWarning("Encountered an <image> element under <rdf:RDF> that was not used in a preceding channel: "+about);
}
else{
unmappedImages.removeElement(about);
inImage = true;
}
}
}
/**
* Handle items that appear to be under syndication (qualified names sstart with "sy:").
* The syndication namespace must be present or an RssParseException will be thrown.
* @param synobj The element that uses syndication.
* @param name
* @param value
*/
protected void handleSyndication(IUsesSyndication synobj, String name, String value) throws RssParseException{
checkSyndication();
RssSyndication syn = synobj.getChannelSyndication();
if(syn==null){
syn = new RssSyndication();
synobj.setChannelSyndication(syn);
}
if("updatePeriod".equals(name)){
syn.setUpdatePeriod(value);
}
if("updateFrequency".equals(name)){
syn.setUpdateFrequency(Integer.parseInt(value));
}
if("updateBase".equals(name)){
try{
syn.setUpdateBase(value);
}
catch(ParseException e){
throw new RssParseException("Syndication update base date value not convertible from ISO8601: '"+value+"'");
}
}
}
/**
* Handle items that appear to be under dublin core (qualified names sstart with "dc:").
* The dublin core namespace must be present or an RssParseException will be thrown.
* @param dcobj The element that uses dublin core.
* @param name
* @param value
*/
protected void handleDublinCore(IUsesDublinCore dcobj, String name, String value) throws RssParseException{
checkDublinCore();
RssDublinCore dc = dcobj.getDublinCore();
if(dc==null){
dc = new RssDublinCore();
dcobj.setDublinCore(dc);
}
if("title".equals(name)){
dc.setTitle(value);
}
if("creator".equals(name)){
dc.setCreator(value);
}
if("subject".equals(name)){
dc.setSubject(value);
}
if("description".equals(name)){
dc.setDescription(value);
}
if("publisher".equals(name)){
dc.setPublisher(value);
}
if("contributor".equals(name)){
dc.setContributor(value);
}
if("date".equals(name)){
try{
dc.setDate(value);
}
catch(ParseException e){
throw new RssParseException( e );
// throw new RssParseException("Dublin Core date value not convertible from ISO8601: '"+value+"'");
}
}
if("type".equals(name)){
dc.setType(value);
}
if("format".equals(name)){
dc.setFormat(value);
}
if("identifier".equals(name)){
dc.setIdentifier(value);
}
if("source".equals(name)){
dc.setSource(value);
}
if("language".equals(name)){
dc.setLanguage(value);
}
if("relation".equals(name)){
dc.setRelation(value);
}
if("coverage".equals(name)){
dc.setCoverage(value);
}
if("rights".equals(name)){
dc.setRights(value);
}
}
/**
* Handle items that appear to be under dublin core (qualified names sstart with "dc:").
* The dublin core namespace must be present or an RssParseException will be thrown.
* @param dcobj The element that uses dublin core.
* @param name
* @param value
*/
protected void handleJbnPatch( IUsesJbnPatch dcobj, String name, String value) throws RssParseException{
checkJbnPatch();
RssJbnPatch jbn = dcobj.getJbnPatch();
if(jbn == null){
jbn = new RssJbnPatch();
dcobj.setJbnPatch(jbn);
}
if( RssJbnPatch.ATTR_TYPE.equals(name)){
jbn.setType( value);
}
else if( RssJbnPatch.ATTR_CREATOR.equals( name ) )
{
jbn.setCreator( value );
}
else if( RssJbnPatch.ATTR_JIRA.equals( name ))
{
jbn.setJira( value );
}
else if( RssJbnPatch.ATTR_MD5.equals( name ) )
{
jbn.setMd5( value );
}
else if( RssJbnPatch.ATTR_SHA256.equals( name ) )
{
jbn.setSha256( value );
}
else if( RssJbnPatch.ATTR_FILE_NAME.equals( name ) )
{
jbn.setFileName( value );
}
else if( RssJbnPatch.ATTR_FILE_SIZE.equals( name ) )
{
jbn.setFileSize( value );
}
else if( RssJbnPatch.ATTR_DOWNLOAD_URL.equals( name ) )
{
jbn.setDownloadUrl( value );
}
else if( RssJbnPatch.ATTR_AUTOMATED_DOWNLOAD_URL.equals( name ) )
{
jbn.setAutomatedDownloadUrl( value );
}
else if( RssJbnPatch.ATTR_INSTRUCTION_VERSION.equals( name ) )
{
jbn.setInstructionCompatibilityVersion( value );
}
else if( RssJbnPatch.ATTR_LONG_DESC.equals( name ) )
{
jbn.setLongDescription( value );
}
else if( RssJbnPatch.ATTR_SHORT_DESC.equals( name ) )
{
jbn.setShortDescription( value );
}
else if( RssJbnPatch.ATTR_MANUAL_INSTALL.equals( name ) )
{
jbn.setManualInstallation( value );
}
else if( RssJbnPatch.ATTR_AUTOMATED_INSTALL.equals( name ) )
{
jbn.setAutomatedInstallation( value );
}
else if( RssJbnPatch.ATTR_CASE_ID.equals( name ) )
{
jbn.setCaseId( value );
}
else if( RssJbnPatch.ATTR_LICENSE_NAME.equals( name ) )
{
jbn.setLicenseName( value );
}
else if( RssJbnPatch.ATTR_LICENSE_VERSION.equals( name ) )
{
jbn.setLicenseVersion( value );
}
else if( RssJbnPatch.ATTR_DISTRIBUTION_STATUS.equals( name ) )
{
jbn.setDistributionStatus( value );
}
else if( RssJbnPatch.ATTR_LAST_UPDATED.equals( name ) )
{
try
{
jbn.setLastUpdated( value );
}
catch ( ParseException e )
{
e.printStackTrace();
}
}
else if( inJbnProducts && RssJbnPatch.ATTR_PRODUCT.equals( name ) )
{
currentJbnDependency.setName( value );
jbn.addProduct( currentJbnDependency );
}
else if( inJbnRequires && RssJbnPatch.ATTR_PATCH.equals( name ) )
{
currentJbnDependency.setName( value );
jbn.addRequires( currentJbnDependency );
}
else if( inJbnReplaces && RssJbnPatch.ATTR_PATCH.equals( name ) )
{
currentJbnDependency.setName( value );
jbn.addReplaces( currentJbnDependency );
}
else if( inJbnIsReplacedBy && RssJbnPatch.ATTR_PATCH.equals( name ) )
{
currentJbnDependency.setName( value );
jbn.addReplacedBy( currentJbnDependency );
}
else if( inJbnCompatibleWith && RssJbnPatch.ATTR_PATCH.equals( name ) )
{
currentJbnDependency.setName( value );
jbn.addReplacedBy( currentJbnDependency );
}
else if( inJbnAutomatedInstallation && RssJbnPatch.ATTR_INSTRUCTION_SET.equals( name ) )
{
currentJbnDependency.setName( value );
jbn.addAutomatedInstallationSet( currentJbnDependency );
}
}
/**
* Obtains the named attribute, whether qualified or not. If the fully qualified attribute is
* not found but the unqualified is, then a warning is added to the document. If it is not
* found at all, then an RssParseException is thrown since this does not adhere to the 1.0 standard.
* @param element
* @param attName
* @param prefix
* @param attrs
* @return the attribute
*/
protected String getAttributeUnqualified(String element, String attName, String prefix, Attributes attrs) throws RssParseException{
String attrValue = getAttribute(attrs, prefix+":"+attName);
if(attrValue==null){
attrValue = getAttribute(attrs, attName);
if(attrValue!=null){
document.addWarning(element+": The use of unqualified attributes (such as '"+attName+"' vs. '"+prefix+":"+attName+"') is deprecated.");
}
else{
throw new RssParseException(prefix+":"+attName+" attribute not present on the <"+element+"> element");
}
}
return attrValue;
}
/**
* Validates that this document has specified Dublin Core in its header
* by examining the namespaces. If it is there, then the method returns
* normally. Otherwise, throws an RssParseException which halts processing.
*/
protected void checkDublinCore() throws RssParseException{
Enumeration enumeration = namespaces.elements();
while(enumeration.hasMoreElements()){
RssNamespace ns = (RssNamespace)enumeration.nextElement();
if(ns!=null){
if(RssDublinCore.PREFIX.equals(ns.getPrefix()) && RssDublinCore.XMLNS_VALUE.equals(ns.getUri())){
return;
}
}
}
throw new RssParseException("Elements were found using Dublin Core but its namespace ("+RssDublinCore.XMLNS+"=\""+RssDublinCore.XMLNS_VALUE+"\") was not specified in the document header");
}
/**
* Validates that this document has specified JBN patch in its header
* by examining the namespaces. If it is there, then the method returns
* normally. Otherwise, throws an RssParseException which halts processing.
*/
protected void checkJbnPatch() throws RssParseException{
Enumeration enumeration = namespaces.elements();
while(enumeration.hasMoreElements()){
RssNamespace ns = (RssNamespace)enumeration.nextElement();
if(ns!=null){
if( RssJbnPatch.PREFIX.equals(ns.getPrefix()) && RssJbnPatch.XMLNS_VALUE.equals(ns.getUri())){
return;
}
}
}
throw new RssParseException("Elements were found using JBN Patch but its namespace ("+RssJbnPatch.XMLNS+"=\""+RssJbnPatch.XMLNS_VALUE+"\") was not specified in the document header");
}
/**
* Validates that this document has specified Syndication in its header
* by examining the namespaces. If it is there, then the method returns
* normally. Otherwise, throws an RssParseException which halts processing.
*/
protected void checkSyndication() throws RssParseException{
Enumeration enumeration = namespaces.elements();
while(enumeration.hasMoreElements()){
RssNamespace ns = (RssNamespace)enumeration.nextElement();
if(ns!=null){
if(RssSyndication.PREFIX.equals(ns.getPrefix()) && RssSyndication.XMLNS_VALUE.equals(ns.getUri())){
return;
}
}
}
throw new RssParseException("Elements were found using Syndication but its namespace ("+RssSyndication.XMLNS+"=\""+RssSyndication.XMLNS_VALUE+"\") was not specified in the document header");
}
/**
* Looks for any leftover items, images or textinputs from within channels that
* have not been 'matched' to items, images and textinputs outside the channels.
* If any are found, then a RssParseException is thrown with its resource
* attribute.
*/
private void checkForLeftovers() throws RssParseException{
if(unmappedItems.size()>0){
String resource = (String)unmappedItems.elements().nextElement();
throw new RssParseException("Item was found in channel but had no corresponding resource: '"+resource+"'");
}
if(unmappedImages.size()>0){
String resource = (String)unmappedImages.elements().nextElement();
throw new RssParseException("Image was found in channel but had no corresponding resource: '"+resource+"'");
}
if(unmappedTextInputs.size()>0){
String resource = (String)unmappedTextInputs.elements().nextElement();
throw new RssParseException("TextInput was found in channel but had no corresponding resource: '"+resource+"'");
}
}
}