📄 litexmlelement.java
字号:
if (-1 != indent) { into.write('\n'); } } // recurse as needed if (recurse) { int childIndent; Enumeration<LiteXMLElement> childrens = getChildren(); Attribute space = getAttribute("xml:space"); if (null != space) { if ("preserve".equals(space.getValue())) { childIndent = -1; } else { childIndent = indent + 1; } } else { if (-1 != indent) { childIndent = indent + 1; } else { childIndent = -1; } } while (childrens.hasMoreElements()) { LiteXMLElement aChild = childrens.nextElement(); aChild.printNice(into, childIndent, recurse); } } // print end tag StringBuilder end = new StringBuilder(); if (-1 != indent) { // do indent for (int eachTab = 0; eachTab < indent; eachTab++) { end.append('\t'); } } end.append(getDocument().docContent.substring(loc.endTag.start, loc.endTag.end + 1)); if (-1 != indent) { end.append('\n'); } into.write(end.toString()); } } /** * Given a source string, an optional tag and a range with in the source * find either the tag specified or the next tag. * <p/> * The search consists of 4 phases : * 0. If no tag was specified, determine if a tag can be found and * learn its name. * 1. Search for the start of the named tag. * 2. Search for the end tag. Each time we think we have found a tag * which might be the end tag we make sure it is not the end tag * of another element with the same name as our tag. * 3. Calculate the position of the body of the tag given the locations * of the start and end. * * @param source the string to search * @param tag the tag to search for in the source string. If this tag is * empty or null then we will search for the next tag. * @param range describes the range of character locations in the source * string to which the search will be limited. * @return tagRange containing the ranges of the found tag. */ protected tagRange getTagRanges(final StringBuilder source, String tag, final charRange range) { // FIXME bondolo@jxta.org 20010327 Does not handle XML comments. ie. <!-- --> if (null != uninserted) { throw new IllegalStateException("This element has not been added to the document."); } tagRange result = new tagRange(); int start = range.start; int end = source.length() - 1; int current; boolean foundStartTag = false; boolean foundEndTag = false; boolean emptyTag = (null == tag) || (0 == tag.length()); // check for bogosity if ((-1 == start) || (start >= end)) { throw new IllegalArgumentException("Illegal start value"); } // adjust end of range if ((-1 != range.end) && (end > range.end)) { end = range.end; } // check for empty tag and assign empty string if (null == tag) { tag = ""; } if (Logging.SHOW_FINER && LOG.isLoggable(Level.FINER)) { LOG.finer("Searching for \"" + tag + "\" in range [" + start + "," + end + "]"); } current = start; // Begin Phase 0 : Search for any tag. if (emptyTag) { int foundTagText = source.indexOf("<", current); // was it not found? if not then quit if (-1 == foundTagText) { if (Logging.SHOW_FINER && LOG.isLoggable(Level.FINER)) { LOG.finer("No Tags Found"); } return result; } // this part is about setting the tag if necessary foundTagText++; int afterTagText = foundTagText; while (afterTagText <= end) { char inTagName = source.charAt(afterTagText); if (!Character.isWhitespace(inTagName) && ('/' != inTagName) && ('>' != inTagName)) { afterTagText++; continue; } tag = source.substring(foundTagText, afterTagText); emptyTag = (null == tag) || (0 == tag.length()); break; } // it better not be still empty if (emptyTag) { if (Logging.SHOW_FINER && LOG.isLoggable(Level.FINER)) { LOG.finer("No tag found"); } return result; } } if (Logging.SHOW_FINER && LOG.isLoggable(Level.FINER)) { LOG.finer("Search for \"" + tag + "\" [" + start + "," + end + "]"); } // Begin Phase 1: Search for the Start Tag while (!foundStartTag && (current < end)) { int foundTagText = source.indexOf(tag, current + 1); // first loc is one past current location int foundTagTerminator; int foundNextTagStart; int afterTagText = foundTagText + tag.length(); // was it not found if ((-1 == foundTagText) || (afterTagText > end)) { if (Logging.SHOW_FINER && LOG.isLoggable(Level.FINER)) { LOG.finer("Tag \"" + tag + "\" Not Found(1)"); } return result; } char checkChar = source.charAt(afterTagText); // check to see if it is the start tag if (('<' != source.charAt(foundTagText - 1)) || // it has the open tag delimiter before it (!Character.isWhitespace(checkChar) && ('/' != checkChar) && ('>' != checkChar))) { // is immediately followed by a delimiter current = afterTagText; continue; } foundTagTerminator = source.indexOf(">", afterTagText); foundNextTagStart = source.indexOf("<", afterTagText + 1); if ((-1 == foundTagTerminator) || // the tag has no terminator (foundTagTerminator > end) || // it is past the valid range ((-1 != foundNextTagStart) && // there is another tag start (foundNextTagStart < foundTagTerminator))) { // and it is before the terminator we found. very bad current = afterTagText; continue; } foundStartTag = true; result.startTag.start = foundTagText - 1; result.startTag.end = foundTagTerminator; } if (!foundStartTag) { if (Logging.SHOW_FINER && LOG.isLoggable(Level.FINER)) { LOG.finer("Tag \"" + tag + "\" Not Found(2)"); } return result; } // is this an empty element declaration? if ('/' == source.charAt(result.startTag.end - 1)) { // end is the start and there is no body result.body = new charRange(result.startTag.start, result.startTag.end); result.endTag = new charRange(result.startTag.start, result.startTag.end); if (Logging.SHOW_FINER && LOG.isLoggable(Level.FINER)) { LOG.finer("Empty Element \"" + tag + "\" Start : " + result.startTag); } return result; } current = result.startTag.end + 1; // if current is past the end then our end tag is not found. if (current >= end) { if (Logging.SHOW_FINER && LOG.isLoggable(Level.FINER)) { LOG.finer("End not found \"" + tag + "\" Start : " + result.startTag); } return result; } // Begin Phase 2 : Search for the end tag String endTag = "</" + tag + ">"; int searchFrom = result.startTag.end + 1; while (!foundEndTag && (current < end) && (searchFrom < end)) { if (Logging.SHOW_FINER && LOG.isLoggable(Level.FINER)) { LOG.finer("Searching for \"" + endTag + "\" in range [" + current + "," + end + "]"); } int foundTagText = source.indexOf(endTag, current); // was it not found or not in bounds? if ((-1 == foundTagText) || ((foundTagText + endTag.length() - 1) > end)) { break; } // it was not found if (Logging.SHOW_FINER && LOG.isLoggable(Level.FINER)) { LOG.finer( "Prospective tag pair for \"" + tag + "\" " + result.startTag + ":[" + foundTagText + "," + (foundTagText + endTag.length() - 1) + "]"); } // We recurse here in order to exclude the end tags of any sub elements with the same name charRange subRange = new charRange(searchFrom, foundTagText - 1); if (Logging.SHOW_FINER && LOG.isLoggable(Level.FINER)) { LOG.finer("Recursing to search for \"" + tag + "\" in " + subRange); } tagRange subElement = getTagRanges(source, tag, subRange); if (Logging.SHOW_FINER && LOG.isLoggable(Level.FINER)) { LOG.finer("Recursion result \"" + tag + "\" " + subElement); } // if there was an incomplete sub-tag with the same name, skip past it if (subElement.startTag.isValid()) { if (Logging.SHOW_FINER && LOG.isLoggable(Level.FINER)) { LOG.finer("Found sub-tag \"" + tag + "\" at " + subElement + " within " + subRange); } if (subElement.endTag.isValid()) { if (Logging.SHOW_FINER && LOG.isLoggable(Level.FINER)) { LOG.finer("Complete sub-tag \"" + tag + "\" at " + subElement + " within " + subRange); } current = subElement.endTag.end + 1; searchFrom = subElement.endTag.end + 1; } else { current = foundTagText + endTag.length(); } continue; } foundEndTag = true; result.endTag.start = foundTagText; result.endTag.end = foundTagText + endTag.length() - 1; if (Logging.SHOW_FINER && LOG.isLoggable(Level.FINER)) { LOG.finer("Prospective tag \"" + tag + "\" " + result.endTag + " is confirmed."); } } // Begin Phase 3 : Calculate the location of the body. result.body.start = result.startTag.end + 1; if (foundEndTag) { result.body.end = result.endTag.start - 1; } else { result.body.end = end; } if (Logging.SHOW_FINER && LOG.isLoggable(Level.FINER)) { LOG.finer("Found element : \"" + tag + "\" " + result); } return result; } /** * Parse a charRange and add any tags found as content as children of a * specified element. This process is repeated recursivly. * * @param scanRange the range to be parsed for sub-tags * @param addTo the element to add any discovered children to. */ protected void addChildTags(final charRange scanRange, LiteXMLElement addTo) { if (null != uninserted) { throw new IllegalStateException("This element has not been added to the document."); } int current = scanRange.start; if (Logging.SHOW_FINER && LOG.isLoggable(Level.FINER)) { LOG.finer("Scanning for children in range " + scanRange); } do { // scan for any tag. tagRange aSubtag = getTagRanges(getDocument().docContent, null, new charRange(current, scanRange.end)); // did we find one? if (aSubtag.isValid()) { LiteXMLElement newChild = getDocument().createElement(aSubtag); if (Logging.SHOW_FINER && LOG.isLoggable(Level.FINER)) { LOG.finer( "Adding child tag \"" + getDocument().docContent.substring(aSubtag.endTag.start + 2, aSubtag.endTag.end) + "\" " + aSubtag); } addTo.appendChild(newChild); if (paranoidConsistencyChecking) { checkConsistency(); } if (!aSubtag.startTag.equals(aSubtag.endTag)) { addChildTags(aSubtag.body, newChild); // recurse into the new tag } // all done this tag, move on current = aSubtag.endTag.end + 1; } else { current = -1; // all done! } } while ((-1 != current) && (current < scanRange.end)); if (paranoidConsistencyChecking) { checkConsistency(); } } /** * For this element and all its children adjust the location of its ranges * by the amount specified. * * @param beginningAt adjust all locations which are at or past this * location. * @param by amount to adjust all matching locations. */ protected void adjustLocations(final int beginningAt, final int by) { if (null != uninserted) { throw new IllegalStateException("This element has not been added."); } // Check that this element is not entirely to the left of the shift // zone. NB: end can be < start if len is 0. if (loc.endTag.end < beginningAt && loc.endTag.start < beginningAt) { return; } if ((loc.startTag.end >= beginningAt) || ((loc.startTag.start >= beginningAt) && ((loc.startTag.end + 1) == loc.startTag.start))) { loc.startTag.end += by; } if (loc.startTag.start >= beginningAt) { loc.startTag.start += by; } if ((loc.body.end >= beginningAt) || ((loc.body.start >= beginningAt) && ((loc.body.end + 1) == loc.body.start))) { loc.body.end += by; } if (loc.body.start >= beginningAt) { loc.body.start += by; } if ((loc.endTag.end >= beginningAt) || ((loc.endTag.start >= beginningAt) && ((loc.endTag.end + 1) == loc.endTag.start))) { loc.endTag.end += by; } if (loc.endTag.start >= beginningAt) { loc.endTag.start += by; } for (Enumeration<LiteXMLElement> eachChild = getChildren(); eachChild.hasMoreElements();) { LiteXMLElement aChild = eachChild.nextElement(); aChild.adjustLocations(beginningAt, by); } if (paranoidConsistencyChecking) { checkConsistency(); } } /** * Given a StringBuilder find all occurrences of escaped characters which * must be decoded and convert them back to their non-escaped equivalents. * <p/> * <p/>Also does end of line folding per: <a href="http://www.w3.org/TR/REC-xml#sec-line-ends"/> * * @param target The StringBuilder which will be decoded. * @return The decoded version of the StringBuilder. */ protected StringBuilder decodeEscaped(StringBuilder target) { int current = 0; StringBuilder result = new StringBuilder(target.length()); while (current < target.length()) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -