package net.jtank.io; import java.util.List; import java.util.ArrayList; import java.util.LinkedList; import java.io.*; import java.net.*; /** * The primary data storage and retrieveal unit for the WXML structure are * WXMLSections. * * WXMLSections are the data storage classes that are the heart of the WXML * tools. Reading and writing the files aside, most operations are performed on * these classes. Each WXMLSection contains a List of sub sections, * which are WXMLSection objects, and a list of attributes which are * WXMLAttribute objects. There are various methods for adding, removing, * retrieving and changing these elemnts. The following is one such example * of how to do this. * * Example:
*
 * ---exampleWXML.wxml---
 * 
 *    foo
 *    
 *       10
 *    
 *    
 *       10
 *    
 * 
 * ---EOF---
 * 
* * You could load the file as such:
* * String directoryBase = (new File("")).getAbsolutePath() + "/";
* try {
* WXML example = WXML.loadFile(directoryBase + "exampleWXML.wxml", null);
* } catch (IOException e) {
* System.out.println("Error reading file.")'
* }
*
*
* To access the main WXMLSection object you will need to retrieve it from the * WXML object, like so:
* * WXMLSection main = example.getSubSection("example");
*
* * Now that you have that, printing out the title say is quite easy. * Notice that title is an attribute as it is a tag with no sub-section. * The "name=1" also represents an attribute for the level in the above example * but this time, it is an in-line attribute.
* * System.out.println(main.getAttributeValue("title"));
*
*
* To get an array of all the levels is also easy:
* * WXMLSection [] levels = main.getSubSectionGroup("level")
* levels[0].getAttributeValue("name"); //print out the name of the first level
*
*
* Hopefully with these examples, you can see the power of the WXML data storage * tools.
* * @author William Denniss * @version 1.1 - 3 April 2002 * * Version History: * (As per WXML.java) * * The tanksoftware package, it's binaries and source code are all licensed * under the GNU GPL. See the accompanying file COPYING for details. * * William Denniss has asserted his right under the Australian Copyright, * Designs and Patents Act 1988 to be identified as the author of this work. */ public class WXMLSection { private WXMLSection parent = null; private List subsections = new ArrayList(); private List attributes = new ArrayList(); //A list contianing all tags (that is sections and non-inline attributes) in the order they were found. private List inOrderSectionTags = new ArrayList(); private String name; public String text; public List getInOrderSectionTags () { return inOrderSectionTags; } public void addInOrderSectionTag (WXMLSection toAdd) { inOrderSectionTags.add(toAdd); } /** * Creates a WXML Section (or tag) with no subsections, nor attributes in it. *@param name The name of the section. This will also be the name in the tag eg when this object is * printed. *@param parent The WXMLSection that contains this one. This can be null if this is the root section. */ public WXMLSection (String name, WXMLSection parent) { this.name = name; this.parent = parent; } /** * Adds an attribute to this WXMLSection. *@param toAdd The attribute to add to this WXMLSection. */ public void addAttribute (WXMLAttribute toAdd) { attributes.add(toAdd); } /** * Removes an attribute from this WXMLSection. *@param toRemove The attribute to be removed. */ public void removeAttribute (WXMLAttribute toRemove) { attributes.remove(toRemove); } public void purgeAll () { subsections = new ArrayList(); attributes = new ArrayList(); } /** * Adds a List of attributes to this WXMLSection. Note: the elements of the List need to be WXMLAttribute objects. * @param toAdd The List of WXMLAttributes to add to this WXMLSection. */ //todo, add checking public void addAttribute (List toAdd) { if (toAdd == null) return; attributes.addAll(toAdd); } /** * Adds an WXMLSection as a subsection to this WXMLSection object. * * @param toAdd The section to add. */ public void addSubSection (WXMLSection toAdd) { //as the last element is normally the empty element, ignore it. if (toAdd == null) return; Object lastSubSection = null; //added if (subsections.size() > 0) { //added lastSubSection = subsections.get(subsections.size()-1);//added subsections.remove(lastSubSection);//added } subsections.add(toAdd); if (lastSubSection != null) {//added subsections.add(lastSubSection);//added } else { subsections.add(new WXMLSection("-=attribute=-", this)); } } //use only when ititialiseing, see the above method for after it is initialised public void addSubSection (List toAdd) { subsections.addAll(toAdd); } public void removeSubSection (WXMLSection toRemove) { subsections.remove(toRemove); } /** * Returns the name of this WXMLSection, normally it's tag name. * @return The name of the tag that this object represents. */ public String getName () { return name; } /** * Searches though the subsections for the one whose name equals the * parsed String. * * @param toFind The name of the sub section that will be searched for. * @return The WXMLSection that is found, or null if none is found. */ public WXMLSection getSubSection (String toFind) { for (int i = 0; i < subsections.size(); i++) { WXMLSection current = (WXMLSection) subsections.get(i); if (current.getName().equals(toFind)) return current; } return null; } /** * This should be used instead of getSubSection(String toFind) whenever * there are multiple occurances of the same tag. It returns an array * containing every sub section that shares the same name as the one you * are searching for, as opposed to just the first instance. * @param groupName The name for the group of sub-sections. * @return An array containing all sub sections whose name is equal to * the one that is being searched for. */ public WXMLSection [] getSubSectionGroup (String groupName) { List groups = new LinkedList(); for (int i = 0; i < subsections.size(); i++) { WXMLSection current = (WXMLSection) subsections.get(i); if (current.getName().equals(groupName)) groups.add(current); } Object [] objects = groups.toArray(); WXMLSection [] toReturn = new WXMLSection[objects.length]; for (int i = 0; i < objects.length; i++) { toReturn[i] = (WXMLSection) objects[i]; } return toReturn; } /** * Returns the value of the given attribute key. * In the case of an inline attribute eg. foo="bar", bar would be * returned. In the case of a text-only tag eg. bar bar * would be returned. * * @param key The key whose value will be returned. * @return The value of the given attribute key or null if it doesn't * exist. */ public String getAttributeValue (String key) { for (int i = 0; i < attributes.size(); i++) { WXMLAttribute current = (WXMLAttribute) attributes.get(i); if (current.getKey().equals(key)) return current.getvalue(); } return null; } /** * Changes the value of the given attribute key, or creates a new * attribute with the given key/value pair should it not already exist. * refer to the getAttributeValue(String) method above for more details * on how attributes work. * * @param key The key of the attribute that will be changed/added. * @param value The value that the key will be changed to. */ public void setAttributeValue (String key, String value) { for (int i = 0; i < attributes.size(); i++) { WXMLAttribute current = (WXMLAttribute) attributes.get(i); if (current.getKey().equals(key)) { current.setValue(value); return; } } attributes.add(new WXMLAttribute(key, value, true)); return; } /** * Same as getAttributeValue(String), but instead of returning null * should the attribute not be found, it returns the given defualt * value. * * @param key The name of the attribute you want to retrieve. * @param defaultValue The default value if that attribute does not * exist. * @return The value of the attribute if found, or the default value if * it isn't. */ public String getAttributeValueWDefault (String key, String defaultValue) { String toReturn = getAttributeValue(key); if (toReturn == null) return defaultValue; else return toReturn; } /** * Same as getAttributeValueWDefault(String, String), but with an int * being returned, and passed as the default. * * @param key The name of the attribute you want to retrieve. * @param defaultValue The default value that is returned if the * attribute is not found. * @return The attribute value, or if it isn't found, the default value. */ public int getAttributeValueWDefaultInt (String key, int defaultValue) { String toReturn = getAttributeValue(key); if (toReturn == null) return defaultValue; else return Integer.parseInt(toReturn); } /** * Converts subsections with no subsections of their own to Attributes. * Eg example would become title=example. */ public void resolveSubSectionAttributes () { //before the tags are resolved, preserve the order inOrderSectionTags = this.subsections; List newsections = new ArrayList (); for (int i = 0; i < subsections.size(); i++) { WXMLSection currentSection = (WXMLSection) subsections.get(i); try { WXMLSection firstSubSectionOfCurrent = (WXMLSection) currentSection.subsections.get(0); // A section is an attribute if it has no attributes, and only contains the text -=attribute=- // This is because any section containing only 1 full line attribute will after that one is resolved, be left with the text -=attribute=- in position 0 // this is because ALL TAGS have their last subsections as the empty subsection. if ( firstSubSectionOfCurrent.name.equals("-=attribute=-") && currentSection.attributes.size() == 0) { //System.out.println("attributefound"); String atext = WXML.replaceChar(firstSubSectionOfCurrent.text,'�','<'); atext = WXML.replaceChar(atext,'�','>'); attributes.add( new WXMLAttribute (currentSection.getName(), atext, false)); } else { newsections.add(currentSection); } } catch (IndexOutOfBoundsException e) { newsections.add(currentSection); } } subsections = newsections; } /** * Returns the String representation of this WXMLSection, starting at indent 0. For more * details, see the print (int indent) method. * * @return The String representation of this WXMLSection. */ public String toString () { return print (0); } /** * Returns the String representation of this WXMLSection. Note: this is * not a WXML format String, and should only be used for debugging * purpouses. * * @param indent The number of tab characters in this section will * start. * @return The String representation of this WXMLSection. */ public String print (int indent) { String toreturn = ""; for (int i = 0; i < indent; i++) toreturn += "\t"; String attributeString = " attributes:"; for (int i = 0; i < attributes.size(); i++) attributeString += ((WXMLAttribute) attributes.get(i)).toString(); toreturn+= "<" + name + ">" + attributeString + "\n"; // As all subsections end with the empty subsection, no need to print it for (int i = 0; i < subsections.size()-1; i++) toreturn += ((WXMLSection) subsections.get(i)).print(indent+1); return toreturn; } /** * Returns the WXML String representation of this WXMLSection, starting at indent 0. For more * details, see the printOrderedWXMLString (int indent) method. * * @return The WXML String representation of this WXMLSection. */ public String toOrderedWXMLString () { return printOrderedWXMLString(0); } /** * Returns the orded WXML String representation of this WXMLSection. * All attributes and sub-sections are pritned out, in the order that * they were read in. Note: This method is still experimental, and not * garenteed to work. * * @param indent The number of tab characters in this section will * start. * @return The Ordered WXML String representation of this WXMLSection. */ public String printOrderedWXMLString (int indent) { //if (name != null) { String toreturn = ""; String indentString = ""; for (int i = 0; i < indent; i++) indentString += "\t"; toreturn += indentString; String inLineAttributeString = ""; for (int i = 0; i < attributes.size(); i++) { WXMLAttribute current = (WXMLAttribute) attributes.get(i); if (current.isInLineAttribute()) inLineAttributeString += current.toString() + " "; } //start tag; toreturn += "<" + this.name + " " + inLineAttributeString + ">\n"; for (int i = 0; i < this.inOrderSectionTags.size(); i++) { WXMLSection current = (WXMLSection) inOrderSectionTags.get(i); if (current.name.equals("-=attribute=-")) { //System.out.println("---88&&&&&&&&&&******"); String atext = current.text; atext = WXML.replaceCharDouble(atext,'<','\\','<'); //System.out.println(atext); toreturn += indentString + atext + "\n"; } else { toreturn += indentString + current.printOrderedWXMLString(indent+1); } } toreturn += indentString + "\n"; return toreturn; } /** * Returns the WXML String representation of this WXMLSection, starting at indent 0. For more * details, see the printWXMLString (int indent) method. * * @return The WXML String representation of this WXMLSection. */ public String toWXMLString () { return printWXMLString(0); } /** * Returns the WXML String representation of this WXMLSection. This consists * of the tag name, its attributes and all of its sub-sections. All * inline attributes are output as inline attributes, and text only tag * ones are printed as text only tags. However, all attributes are printed * before the sub0section. If you do not want this * see the printOrderedWXMLString() method. * * @param indent The number of tab characters in this section will * start. * @return The WXML String representation of this WXMLSection. */ public String printWXMLString (int indent) { String toreturn = ""; if (name != null) { String indentString = ""; for (int i = 0; i < indent; i++) indentString += "\t"; toreturn += indentString; String inLineAttributeString = ""; String subSectionAttributeString = ""; for (int i = 0; i < attributes.size(); i++) { WXMLAttribute current = (WXMLAttribute) attributes.get(i); if (current.isInLineAttribute()) { inLineAttributeString += current.toString(); } else { //System.out.println("---888******************"); subSectionAttributeString += "<" + current.key + ">" + WXML.replaceCharDouble(current.value,'<','\\','<') + "\n"; } } toreturn+= "<" + name + " " + inLineAttributeString + ">" + "\n"; toreturn+= subSectionAttributeString; // As all subsections end with the empty subsection, no need to print it for (int i = 0; i < subsections.size()-1; i++) toreturn += ((WXMLSection) subsections.get(i)).printWXMLString(indent+1); toreturn += indentString + "\n"; return toreturn; } else { for (int i = 0; i < subsections.size()-1; i++) toreturn += ((WXMLSection) subsections.get(i)).printWXMLString(indent); return toreturn; } } /** * A WXML Key-Value pair (eg "width=10") that can either be embedded in a tag, or have one of it's own. */ public static class WXMLAttribute { private String key; private String value; private boolean inLineAttribute; /** * Creates a new WXMLAttribute. * * @param key The name, or key of this attribute. * @param value The value associated with that name. * @param inLineAttribute Whether or not this attribute is in the tag eg */ public WXMLAttribute (String key, String value, boolean inLineAttribute) { this.key = key; this.value = value; this.inLineAttribute = inLineAttribute; // this. // this.name = "!@Attribute@!"; } /** * Changes the current key to the new specified new one. * * @param key The new name, or key of this attribute. */ public void setKey (String key) { this.key = key; } /** * Changes the current value to the new specified new one. * * @param value The new value of this attribute. * */ public void setValue (String value) { this.value = value; } /** * Gets the key of this WXMLAttribute * *@return The key of this WXMLattribute */ public String getKey () { return key; } /** * Gets the value of this WXMLAttribute * *@return The value of this WXMLattribute */ public String getvalue () { return value; } /** * Returns the String representation of this object. * *@return The String representation of this object. */ public String toString () { String avalue = WXML.replaceCharDouble(value,'\"','\\','\"'); avalue = WXML.replaceCharDouble(avalue,'>','\\','>'); return key + "=\"" + avalue + "\" "; } /** * Returns true if this attribute is an inline attribute, * false if it is not. * * @return true if this attribute is an inline attribute, * false if it is not. */ public boolean isInLineAttribute () { return this.inLineAttribute; } } }