XMLDocument.java revision fb379c70e3fd8a537f311b99be4759ae41e02750
/**
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 2006 Sun Microsystems Inc. All Rights Reserved
*
* The contents of this file are subject to the terms
* of the Common Development and Distribution License
* (the License). You may not use this file except in
* compliance with the License.
*
* You can obtain a copy of the License at
* See the License for the specific language governing
* permission and limitations under the License.
*
* When distributing Covered Code, include this CDDL
* Header Notice in each file and include the License file
* at opensso/legal/CDDLv1.0.txt.
* If applicable, add the following below the CDDL Header,
* with the fields enclosed by brackets [] replaced by
* your own identifying information:
* "Portions Copyrighted [year] [name of copyright owner]"
*
* $Id: XMLDocument.java,v 1.3 2008/06/25 05:51:31 qcheng Exp $
*
*/
/**
* Represents a simple XML document in memory that may be edited and stored.
* This implementation relies exlusively on the syntactic correctness of the
* underlying document such as balancing of quotes and delimiters etc. If an
* XML document meets these requirements, it can be used to instantiate this
* class and can then be edited using the public methods available in this
* class as well as in <code>XMLElement</code> class.
* <p>
* The in-memroy XML representation does not include any meta information such
* as <code>DOCTYPE</code> tags, processing instructions, or any commets. Such
* tags are filtered out before the final in-memory representation of the XML
* document is constructed. However, when this document is saved, these meta
* information tags are re-inserted in the appropriate places so as to preserve
* the original format of the document in all respects possible. Even white
* spaces are preserved as far as possible.
* </p>
* <p>
* third party libraries.
* </p>
*/
public class XMLDocument implements IXMLUtilsConstants {
/**
* Creates an instance of XMLDocument using the specified <code>File</code>
* object. No checking is done to ensure the availablity and readability of
* the file passed in as the argument. It is expected that the caller has
* completed such checks and taken the necessary backups before creating
* this instance.
*
* @param file
* representing the XML document on file system.
* @throws Exception
* in case an error occurse during the parsing of this
* document.
*/
}
/**
* Returns the root element for the given XML document. This element
* represents the entire XML document in memory and can be used to traverse
* and edit various portions of the document.
*
* @return the root element of the XML tree
*/
public XMLElement getRootElement() {
return root;
}
/**
* A factory method used for the creation of new XML elements that can be
* added to this XML document at a later stage. When this method is called,
* a new <code>XMLElement</code> object is returned to the caller.
* However, this newly created element is still not attached to the
* document anywhere and it is the responsiblity of the caller to attach it
* in the appropriate location.
*
* @param name
* the name of the new element to be created
* @return the newly created element that can be added to the document
* @throws Exception
* in case the creation of the new element fails due to any
* reason
*/
}
/**
* A factory method used for the creation of new XML elements that can be
* added to this XML document at a later stage. When this method is called,
* a new <code>XMLElement</code> object is returned to the caller.
* However, this newly created element is still not attached to the
* document anywhere and it is the responsiblity of the caller to attach it
* in the appropriate location. Further, the element returned from this
* method is a collapsed element that is contained within a single bounded
* token.
*
* @param name
* the name of the new element to be created
* @return the newly created element that can be added to the document
* @throws Exception
* in case the creation of the new element fails due to any
* reason
*/
}
/**
* A factory method used for the creation of new XML elements that can be
* added to this XML document at a later stage. When this method is called,
* a new <code>XMLElement</code> object is returned to the caller.
* However, this newly created element is still not attached to the
* document anywhere and it is the responsiblity of the caller to attach it
* in the appropriate location. Note that the supplied parameter
* <code>xmlFragement</code> must be a valid well-formed xml element.
*
* @param xmlFragment
* the xml fragment which will be parsed into an element
* @return the newly created element that can be added to the document
* @throws Exception
* in case the creation of the new element fails due to any
* reason
*/
throws Exception {
throw new Exception("Failed to parse fragment into new element");
}
}
/**
* A factory method used for the creation of new XML elements that can be
* added to this XML document at a later stage. When this method is called,
* a new <code>XMLElement</code> object is returned to the caller.
* However, this newly created element is still not attached to the
* document anywhere and it is the responsiblity of the caller to attach it
* in the appropriate location.
*
* @param name
* the name of the new element to be created
* @param value
* the value of the new element to be created
* @return the newly created element that can be added to the document
* @throws Exception
* in case the creation of the new element fails due to any
* reason
*/
}
/**
* Stores the in-memory XML data to the file system.
*
* @throws Exception
* If the save operation did not succeed.
*/
try {
}
throw ex;
} finally {
}
}
}
/**
* Sets the number of spaces used for denoting one indent level. The
* default indent level is set to <code>4</code> spaces. However, this can
* be changed by calling this method anytime. This value comes into effect
* only when any new element is added to the XML document.
*
* @param spaces
* the number of spaces used to denote one level of indentation
*/
public void setIndentDepth(int spaces) {
}
/**
* Sets a flag that is used by the document to indent value tokens when
* adding child elements that have value. The default behavior is to indent
* value tokens, but that can be changed to no indent by calling this
* method.
*
*/
public void setNoValueIndent() {
indentValueTokenFlag = false;
}
/**
* Sets a flag that is used by the document to indent value tokens when
* adding child elements that have value. The default behavior is to indent
* value tokens, but changed by calling <code>setNoValueIndent</code>
* method, it can be reset back to its original state by calling this
* method.
*
*/
public void setValueIndent() {
indentValueTokenFlag = true;
}
/**
* Returns the DOCTYPE string associated with the first DOCTYPE element
* present in this document. This method may return null if no DOCTYPE
* token is already present in the document.
*
* @return
*/
public String getDoctypeString() {
}
return result;
}
/**
* This methods provides a means to update the DOCTYPE element of the
* document with a new value as supplied in the argument. This method will
* throw an Exception if the given document does not contain a predefined
* DOCTYPE element.
*
* @param newDoctypeString
* @throws Exception
*/
{
} else {
throw new Exception("FAILED to update DOCTYPE - no such element");
}
}
/**
* Adds a value token for the given element with the given value.
*
* @param element
* @param value
* @throws Exception
*/
throws Exception {
boolean added = false;
int insertIndex = i + 1;
getParser().getNextTokenIndex());
insertIndex++;
added = true;
break;
}
}
if (!added) {
throw new Exception("Failed to add value token");
}
}
/**
* Adds the given XMLElement after the token whoes index matches the given
* lastTokenIndex value. If the flag addAfterNewLine is true, a new line is
* added before the addition of the new element to this document.
*
* @param lastTokenIndex
* @param element
* @param addAfterNewLine
* @throws Exception
*/
boolean addAfterNewLine) throws Exception {
true);
}
/**
* Adds the given XMLElement after the token whoes index matches the given
* lastTokenIndex value. If the flag addAfterNewLine is true, a new line is
* added before the addition of the new element to this document.
*
* @param lastTokenIndex
* @param element
* @param addAfterNewLine
* @param addOuterWhitespace
* @throws Exception
*/
boolean addAfterNewLine, boolean addOuterWhitespace)
throws Exception {
if (addAfterNewLine) {
}
boolean outerIndent = true;
if (!addOuterWhitespace) {
outerIndent = false;
}
boolean added = false;
int lastIndexPosition = i;
while (nextToken instanceof WhiteSpaceToken) {
}
if (addAfterNewLine) {
}
}
added = true;
break;
}
}
if (!added) {
throw new Exception("Parent element not found: index "
+ lastTokenIndex);
}
}
/**
* Inserts the ending token for a given element which was initially added
* or parsed into a collapsed element.
*
* @param element
* @throws Exception
*/
boolean added = false;
added = true;
break;
}
}
if (!added) {
throw new Exception("Failed to add end token for element: "
+ element);
}
}
/**
* Deletes the tokens from the token whoes index matches with startIndex
* upto the token whoes index matches with endIndex. Both these tokens are
* included in the deletion as well.
*
* @param startIndex
* @param endIndex
* @throws Exception
*/
boolean delete = false;
int deleteCount = 0;
if (!delete) {
&& lastToken instanceof WhiteSpaceToken) {
}
deleteCount++;
if (startIndex != endIndex) {
delete = true;
}
}
} else {
deleteCount++;
delete = false;
break;
}
}
}
if (delete == true) {
throw new Exception("Failed to find last token: index " +
endIndex);
}
throw new Exception("Failed to delete tokens for range: "
}
throw new Exception("Failed to delete token at index: "
}
}
/**
* Returns an xml fragment that represents this element and any contained
* child elements.
*
* @param beginTokenIndex
* the index of the token where the string begins
* @param endTokenIndex
* the index of the token where the string ends
* @return an xml fragment representing this element
*/
int index = 0;
boolean inRange = false;
if (!inRange) {
inRange = true;
}
}
if (inRange) {
inRange = false;
}
}
}
}
/**
* Factory method for creation a new value token with the given value.
*
* @param value
* @return
* @throws Exception
*/
value = "";
}
return valueToken;
}
/**
* Factory method for creating a new element with the given name, given
* value and given attributes. The value and the attributes may be null.
*
* @param name
* @param value
* @param attributes
* @return
* @throws Exception
*/
}
/**
* Factory method for creating a new element with the given name, given
* value and given attributes. The value and the attributes may be null. If
* the boolean argument <code>collapsed</code> is set to true, the element
* will have a single token for start and end marks. In this case if a
* value is specified, it will result in the throwing of an exception to
* indicate an invalid request.
*
* @param name
* @param value
* @param attributes
* @param collapsed
* @return
* @throws Exception
*/
if (collapsed) {
} else {
}
if (collapsed) {
throw new Exception(
"Cannot add a collapsed element with specified value");
}
}
if (!collapsed) {
}
}
}
return result;
}
/**
* Returns the indent level for the given token.
*
* @param tokenIndex
* @return
*/
private int getIndentLevel(int tokenIndex) {
}
/**
* Returns a whitespace string which represents the indentation to be used
* for a given indentLevel value.
*
* @param indentLevel
* @return
*/
for (int i = 0; i < indentLevel; i++) {
}
}
/**
* Returns a string with the number of spaces corresponding to the indent
* depth set for this document.
*
* @return
*/
private String getIndentIncrementString() {
for (int i = 0; i < getIndentDepth(); i++) {
}
}
/**
* Initializes the document with the given File object.
*
* @param file
* @throws Exception
*/
initXMLTree();
if (nextToken instanceof DoctypeToken) {
break;
}
}
}
/**
* Returns the DOCTYPE token associated with this document. May return
* <code>null</code> if no such token is present.
*
* @return
*/
private DoctypeToken getDoctypeToken() {
int doctypeTokenIndex = getDoctypeTokenIndex();
if (doctypeTokenIndex != -1) {
break;
}
}
}
return result;
}
/**
* Creats an in-memory XML tree based on the parsed tokens in this
* document.
*
* @throws Exception
*/
private void initXMLTree() throws Exception {
throw new Exception("More than one root elements encountered");
}
}
/**
* Returns a list of tokens that do not contain any whitespace tokens.
*
* @param rawTokens
* @return filtered tokens
*/
if (nextToken instanceof BoundedToken
|| nextToken instanceof UnboundedToken) {
}
}
}
return filteredTokens;
}
/**
* Updates the tokens to create a set of filtered tokens that make up the
* various XML elements etc for final creation of in-memory XML
* representation.
*/
private void updateFilteredTokens() {
}
/**
* Returns the attributes from the given attribute string.
*
* @param attributeString
* @return
* @throws Exception
*/
}
/**
* Returns the attributes from the given attribute strings of the starting
* and the ending tokens of any element.
*
* @param attributeStringBegin
* @param attributeStringEnd
* @return
* @throws Exception
*/
if (attributeStringBegin != null
}
if (attributeStringEnd != null
}
}
/**
* Walks through the filtered token set to create an in-memory
* representation of the XML document.
*
* @param tokenList
* @return
* @throws Exception
*/
int count = 0;
if (!(firstToken instanceof BoundedToken)) {
throw new Exception("First token not bounded: "
+ firstToken.toDebugString());
}
if (token.elementComplete()) {
.getAttributeString()));
count++;
} else {
if (secondToken instanceof BoundedToken) {
if (!secondBoundedToken.elementStart()) {
if (secondBoundedToken.getName()
.equals(elementName)) {
if (secondBoundedToken.elementEnd()) {
element = new XMLElement(this,
.getAttributeString()));
} else {
throw new Exception("Malformed element: "
.toDebugString());
}
}
}
}
}
}
if (midToken instanceof UnboundedToken) {
}
if (elementValue != null) {
if (!(thirdToken instanceof BoundedToken)) {
throw new Exception("Malformed token encountered: "
+ thirdToken.toDebugString());
}
throw new Exception("Malformed token encountered: "
+ thirdToken.toDebugString());
}
if (!thirdBoundedToken.elementEnd()) {
throw new Exception("Malformed token encountered: "
+ thirdToken.toDebugString());
}
.getAttributeString()));
}
}
int boundCount = 1;
if (nextToken instanceof BoundedToken) {
{
if (nextBoundedToken.elementEnd()) {
if(!nextBoundedToken.elementStart()) {
boundCount--;
if (boundCount == 0) {
element = new XMLElement(this,
.getAttributeString()));
count = i + 1;
break;
} else {
}
} else {
}
} else {
boundCount++;
}
} else {
}
} else {
}
}
throw new Exception("Element not terminated: "
+ elementName + ", innerTokens = "
+ innerTokens);
}
}
}
}
return result;
}
/**
* Returns the raw tokens for this document.
*
* @return
*/
private ArrayList getRawTokens() {
return rawTokens;
}
/**
* Sets the raw tokens for this document.
*
* @param rawTokens
*/
}
/**
* Sets the filtered tokens for this document.
*
* @param filteredTokens
*/
this.filteredTokens = filteredTokens;
}
/**
* Returns the filted tokens for this document.
*
* @return
*/
private ArrayList getFilteredTokens() {
return filteredTokens;
}
/**
* Sets the root element of this document.
*
* @param root
*/
}
/**
* Sets the parser to be used with this document.
*
* @param parser
*/
}
/**
* Returns the parser that is used with this document.
*
* @return
*/
return parser;
}
/**
* Sets the file object which is the source of this document.
*
* @param file
*/
documentFile = file;
}
/**
* Returns the file object that is the source of this document.
*
* @return
*/
private File getDocumentFile() {
return documentFile;
}
/**
* Returns the preffered indentation depth of this document.
*
* @return
*/
private int getIndentDepth() {
return indentDepth;
}
/**
* Returns true if the value token should be indented while adding new
* elements to this document, false otherwise.
*
* @return
*/
private boolean indentValueToken() {
return indentValueTokenFlag;
}
/**
* Sets the document type token index
*
* @param index
*/
private void setDoctypeTokenIndex(int index) {
}
/**
* Returns the document type token index. May return <code>-1</code> if no
* document type token was found.
*
* @return
*/
private int getDoctypeTokenIndex() {
return doctypeTokenIndex;
}
private File documentFile;
private ArrayList filteredTokens;
private XMLElement root;
private int indentDepth = 4;
private boolean indentValueTokenFlag = true;
private int doctypeTokenIndex = -1;
}