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 + "" + this.name + ">\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,'<','\\','<') + "" + current.key + ">\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 + "" + name + ">\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;
}
}
}