Currently showing src/net/jtank/io/WXML.java
package net.jtank.io;

import java.util.List;
import java.util.ArrayList;
import java.util.LinkedList;
import java.io.*;
import java.net.*;

import net.jtank.util.Delegate;

/**
 * WXML is a way of storing and transferring data in a hierarchical text format
 * It can't yet be technically called XML, as it does not nessesarily accept all
 * well-formed XML documents, it does handle most.
 *
 *
 * The WXML class contains some nessesary methods that relate to creating,
 * reading and writing the WXML file format.  WXML is not XML, but is
 * syntactically very similar.
 *
 *
 * @author William Denniss
 * @version 1.1 - 3 April 2002
 *
 * Version History:
 * 1.0 - 15 March 2002: Started.
 * 1.0 - 17 March 2002: Fully Functional.
 * 1.1 - 3 April 2002: TSFS integration added.
 *
 *
 * 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 WXML extends WXMLSection {

	/**
      	 * Creates an empty WXML object, with no name, and no parent WXMLSection.
     	 */
	public WXML () {
		super(null,null);
	}

	public static final int numTests = 4;
	
	/**
	 * An example case.  The file is read in, and then outputted to the screen.
	 * Ideally, this output should semantically match the input.
	 * @param args The arguments parsed into this method.
	 */
	public static final void main (String [] args) {
		int numTests = WXML.numTests;
		try {
		numTests = Integer.parseInt(args[0]);
		} catch (Exception e) {}
		
		for (int i = 1; i < numTests+1; i++) {
			try {
				System.out.println("loading test " + i); 
				WXML newX = WXML.loadFile("data/WXML/test" + i + ".wxml");
				System.out.println("test " + i + " loaded");
				System.out.println("---");
				System.out.println(newX.toWXMLString());
				System.out.println("---");
				System.out.println(newX.toOrderedWXMLString());
				System.out.println("|||");
			} catch (IOException e) {
				System.out.println("IO error reading file");
			} catch (Exception e) {
				System.out.println("General Exception ---------");
				e.printStackTrace();
				System.out.println("|-------------|");
			}
		}
	
	}

	
	/*
	public static String toEscape (String unEscaped) {
		String toReturn = "";
		for (int i = 0; i < unEscaped.length(); i++) {
			if (unEscaped.charAt(i) == '=' || // equals 
			  unEscaped.charAt(i) == '\\' ||  // backslash
			  unEscaped.charAt(i) == '<' ||  // less than
			  unEscaped.charAt(i) == '>') {  //greater than
				toReturn = toReturn + "\\" + unEscaped.charAt(i);
			} else {
				toReturn = toReturn + unEscaped.charAt(i);
			}
		}		
		return toReturn;
	}
	
	public static String fromEscape (String escaped) {
		String toReturn = "";
		int slash = 0;
		for (int i = 0; i < escaped.length(); i++) {
			if (escaped.charAt(i) != '\\' || slash > 0) {
				toReturn = toReturn + escaped.charAt(i);
				if (slash > 0)
					slash = 0;
			} else {
				slash++;
			}
		}
		
		return toReturn;
	
	}
	*/
	
	/**
     	 * Loads a WXML formatted file into a new WXML object.
     	 *
     	 * @param filename The String which points to the name of the file to load.
     	 * @param fileSystem The TSFS file system to use, can be null if none are being
     	 * used.
     	 * @return The WXML Object containing the file data, or null if there was an error.
         * @throws IOException If there is an error reading the file.
	 */
	public static WXML loadFile (String filename) throws IOException {
		String contents = "";

		/*
		 * Reads the entire file that is given into a string with no line breaks.
		 */

			BufferedReader br = null;

			FileUtil.getFileSpecificBufferedReader(filename);

		    String line = br.readLine();

			//todo: try putting line + "\n" back in.
		    while (line != null) {
		      contents += line + " \n";//" ";
		      line = br.readLine();
		    }


		return parseString (contents);


	}

    /**
     * Parses a WXML formatted String into a WXML object.  It does this by recursivly
     * adding the current WXML tag, and parsing the remaining text.  A tag which
     * contains only text and no other tags is considered an attribute.
     *
     * @param contents The WXML formatted String to parse.
     * @return That String, as loaded into a WXML object.
     */
    public static WXML parseString (String contents) {
		/*
		 * Starts off the recursion method which will build the WXML tree.
		 */
		WXML toAdd = new WXML ();
		
		contents = replaceDoubleChar(contents,'\',';','½');
		contents = replaceDoubleChar(contents,'\','>','½');
		
		
		toAdd.addSubSection(parseSection(contents,null));
		return toAdd;
	}

	//given a list of tags, eg <level><title>asdf</title><diff>90</diff></level><balls><number>40</number></balls>
	// it will recursivly create sections and subsections for the first tag (level), then for all of the rest (balls)
	/**
	 * Recursivly builds a List containing all of the WXMLSections as
	 * they appear in the parsed text.  This text would be in WXML format,
	 * eg. <level><title><bold>foo</bold></title><comment>bar</comment></level>.
	 * That String would give 2 WXMLSections in the returned List file, the
	 * first with a sub-section.
	 *
	 * @param toParse The String containing the WXML tags.
	 * @param parent The parent object to which these tags belong.
	 * @return A list containing the WXMLSections from the parsed String.
	 */
	public static List parseSection (String toParse, WXMLSection parent) {

		WXMLSection currentSection;
		List toReturn = new ArrayList();

		String currentTag = "";
		String currentTagInlineAttributes = "";
		String currentSectionText = "";

		int i = 0;

		// Skip to the first tag
		try {
			while (toParse.charAt(i) != ';')
				i++;

		// There are no further tags, only text ie, it is an attribute
		} catch (StringIndexOutOfBoundsException e) {
			WXMLSection toAdd = new WXMLSection ("-=attribute=-",parent);
			toAdd.text = toParse;
			//toAdd.addInOrderSectionTag
			toReturn.add(toAdd);
			return toReturn;

		}

		// Gets the text of the first tag
		i++;
		while (toParse.charAt(i) != ' ' && toParse.charAt(i) != '>') {
			currentTag += toParse.charAt(i);
			i++;
		}

		//System.out.println("++" + currentTag);

		// gets the inline attributes of the first tag
		if (toParse.charAt(i) == ' ') {
			while (toParse.charAt(i) != '>') {
				currentTagInlineAttributes += toParse.charAt(i);
				i++;
			}
		}
		i++;

		//System.out.println("++" + currentTagInlineAttributes);

		// gets all of the text contined in the tag
		try {

			while (!toParse.substring(i,currentTag.length() + 3 + i).equalsIgnoreCase("</" + currentTag + ">")) {
				//System.out.println("=" + toParse.substring(i,currentTag.length() + 3 + i) + "=." + "</" + currentTag + ">" + ".=");
				currentSectionText += toParse.charAt(i);
				i++;
			}
			//System.out.println("oooo3563456365365ooooooo");
		} catch (Exception e) {/*System.out.println("ooooooooooo");*/};

		String remainder = "";

		// gets all of the text after the tag
		try {

			remainder = toParse.substring(currentTag.length() + 4 + i, toParse.length());
			} catch (Exception e) {/*System.out.println("pppp");*/};

		//System.out.println("+++" + currentSectionText);
		//System.out.println("++-+" + remainder);


		// Create new Section
		WXMLSection toAdd = new WXMLSection(currentTag, parent);

		toAdd.text = currentSectionText; // Add the text

		toAdd.addAttribute(inlineAttributeParser(currentTagInlineAttributes)); 		// Add attributes

		toAdd.addSubSection(parseSection (currentSectionText, parent)); // Add sub-sections


		// Add this subsection to the list to be returned
		toReturn.add( toAdd);

		// Add any other sections that were after this one to the list to be returned
		toReturn.addAll(parseSection(remainder, parent));

		/*
		 * NOTE that Sections containing only text and no sub-sections are considered
		 * attributes, and at some stange need to be converted as such;
		 *
		 * todo: attribute resolution for inline and tagged attributes
		 */


		for (int l = 0; l < toReturn.size(); l++ )
	((WXMLSection) toReturn.get(l)).resolveSubSectionAttributes();


		return toReturn;

	}

	public static String replaceChar (String toReplace, char from, char to) {
		String toReturn = "";
		for (int i = 0; i < toReplace.length(); i++) {
			if (toReplace.charAt(i) == from) {
				toReturn += to;
			} else {
				toReturn += toReplace.charAt(i);
			}
			
		}
		return toReturn;
	}
	
	public static String replaceCharDouble (String toReplace, char from, char to1, char to2) {
		String toReturn = "";
		for (int i = 0; i < toReplace.length(); i++) {
			if (toReplace.charAt(i) == from) {
				toReturn += to1 + "" + to2;
			} else {
				toReturn += toReplace.charAt(i);
			}
			
		}
		return toReturn;
	}
	
	public static String replaceDoubleChar (String toReplace, char from1, char from2, char to) {
		String toReturn = "";
		for (int i = 0; i < toReplace.length()-1; i++) {
			if (toReplace.charAt(i) == from1 && toReplace.charAt(i+1) == from2) {
				toReturn += to;
				i++;
			} else {
				toReturn += toReplace.charAt(i);
				if (i == toReplace.length()-2)
					toReturn += toReplace.charAt(i+1);
			}
			
		}
		return toReturn;
	}	
	
    /**
     * Parses a list of attributes that are embedded in a tag, eg <example text1="bob">
     *
     * @param toParse The String to parse for attributes
     * @return A List of WXMLAttribute objects which are all of the attributes
     * that were found in the tag
     */
	public static List inlineAttributeParser (String toParse) {

		List toReturn = new ArrayList ();
		
		//System.out.println("1:" + toParse + "<");
		toParse = replaceDoubleChar(toParse, '\','"','½');
		//System.out.println("2:" +toParse + "<");
		
		
		String spacesInAttribute = "";

		// Temporarily remove spaces

		int j = 0;
		while (j < toParse.length()) {
			if (toParse.charAt(j) == '"') {

				spacesInAttribute += toParse.charAt(j);
				j++; //�
				while (toParse.charAt(j) != '"') {
					if (toParse.charAt(j) == ' ')
						spacesInAttribute += '½';
					else if (toParse.charAt(j) == '=')
						spacesInAttribute += '½';
					else
						spacesInAttribute += toParse.charAt(j);

					j++;
				}

				spacesInAttribute += toParse.charAt(j);
				j++;
			} else {
				spacesInAttribute += toParse.charAt(j);
				j++;
			}
		}

		String [] attributes = Delegate.stringCarver(spacesInAttribute, " ");
		//System.out.println(spacesInAttribute + "========================");
		//System.out.println(attributes.length);

		for (int i = 0; i < attributes.length; i++) {

			String currentAttribute = "";

			//insert spaces back in
			for (int k = 0; k < attributes[i].length(); k++) {
				if (attributes[i].charAt(k) == '½')
					currentAttribute += ' '; //re-insert spaces
				else if (attributes[i].charAt(k) == '"')
					currentAttribute += ""; //cut out "'s
				else
					currentAttribute += attributes[i].charAt(k);

			}

			
			String key = Delegate.carvePos(currentAttribute,0,"=");
			String value =  Delegate.carvePos(currentAttribute,1,"=");
			value = replaceChar(value, '½','"'); 
			value = replaceChar(value, '½','=');
			value = replaceChar(value, '½',';');
			value = replaceChar(value, '½','>');
			
			//value = fromEscape(value);
			toReturn.add(new WXMLAttribute (key, value, true));
			//System.out.println("key:" + key + "value:" + value);
		}

		return toReturn;
	}

}


     

Total 411 Lines of Code.
Source code formatted using showsrc by William Denniss