📄 litexmlelement.java
字号:
// FIXME bondolo@jxta.org 20010422 Should process xml comments out here. // fold 0x0D and 0x0D 0x0A to 0x0A if ('\r' == target.charAt(current)) { result.append('\n'); current++; if ((current < target.length()) && ('\n' == target.charAt(current))) { current++; } continue; } if ('&' != target.charAt(current)) { result.append(target.charAt(current)); current++; continue; } int terminusAt = current + 1; while ((terminusAt < target.length()) && // dont go past end ((terminusAt - current) < 6) && // only look 6 chars away. (';' != target.charAt(terminusAt))) { // must be a ; terminusAt++; } if ((terminusAt >= target.length()) || (';' != target.charAt(terminusAt))) { // if we get here then we didnt find the terminal we needed // so we just leave ampersand as it was, the document is // ill-formed but why make things worse? result.append(target.charAt(current)); current++; continue; } char[] sub = new char[terminusAt - current + 1]; target.getChars(current, terminusAt + 1, sub, 0); String escaped = new String(sub); if ("&".equals(escaped)) { result.append('&'); current += 4; } else if ("<".equals(escaped)) { result.append('<'); current += 3; } else if (">".equals(escaped)) { // for compatibility with SGML. We dont encode these result.append('>'); current += 3; } else if (escaped.startsWith("&#")) { String numericChar = escaped.substring(2, escaped.length() - 1); // is it &#; ? if (numericChar.length() < 1) { result.append(target.charAt(current)); current++; continue; } // is it hex numeric if (numericChar.charAt(0) == 'x') { numericChar = numericChar.substring(1); // is it &#x; ? if (numericChar.length() < 1) { result.append(target.charAt(current)); current++; continue; } try { char asChar = (char) Integer.parseInt(numericChar.toLowerCase(), 16); result.append(asChar); current += escaped.length(); } catch (NumberFormatException badref) { // it was bad, we will just skip it. result.append(target.charAt(current)); current++; } continue; } // its base 10 try { char asChar = (char) Integer.parseInt(numericChar, 10); result.append(asChar); current += escaped.length(); } catch (NumberFormatException badref) { // it was bad, we will just skip it. result.append(target.charAt(current)); current++; } continue; } else { // if we get here then we didn't know what to do with the // entity. so we just send it unchanged. result.append(target.charAt(current)); current++; continue; } current++; } return result; } /** * Given a StringBuilder find all occurrences of characters which must be * escaped and convert them to their escaped equivalents. * * @param target The StringBuilder which will be encoded in place. */ protected void encodeEscaped(StringBuilder target) { int current = 0; while (current < target.length()) { if ('&' == target.charAt(current)) { target.insert(current + 1, "amp;"); current += 5; } else if ('<' == target.charAt(current)) { target.setCharAt(current, '&'); target.insert(current + 1, "lt;"); current += 4; } else { current++; } } } /** * Returns an enumerations of the attributes associated with this object. * Each element is of type Attribute. * * @return Enumeration the attributes associated with this object. */ public Enumeration<Attribute> getAttributes() { List<Attribute> results = new ArrayList<Attribute>(); if (null != uninserted) { throw new IllegalStateException("This element has not been added."); } if (paranoidConsistencyChecking) { checkConsistency(); } // find the start of the first attribute int current = loc.startTag.start + 1; while (current <= loc.startTag.end) { char inTagName = getDocument().docContent.charAt(current); if (Character.isWhitespace(inTagName) || ('/' == inTagName) || ('>' == inTagName)) { break; } current++; } // loop and add attributes to the vector while (current < loc.startTag.end) { tagRange nextAttr = getAttributeLoc(null, new charRange(current, loc.startTag.end)); if (!nextAttr.isValid()) { break; } results.add( new Attribute(this, getDocument().docContent.substring(nextAttr.startTag.start, nextAttr.startTag.end + 1) , getDocument().docContent.substring(nextAttr.body.start, nextAttr.body.end + 1))); current = nextAttr.endTag.end + 1; } return Collections.enumeration(results); } /** * Returns the tagRange of the next attribute contained in the range * provided. The tag range returned consists of the startTag indicating * the location of the name, body indicating the location of the value and * endTag indicating the location of the final quote delimiter. * * @param name Name to match. null means match any name. * @param inRange the limits of the locations to scan. * @return tagRange containing the location of the next attribute */ protected tagRange getAttributeLoc(String name, charRange inRange) { tagRange result = new tagRange(); int current = inRange.start; do { // skip the whitespace while (current <= inRange.end) { char inTagName = getDocument().docContent.charAt(current); if (!Character.isWhitespace(inTagName) && ('/' != inTagName) && ('>' != inTagName)) { break; } current++; } int equalsAt = getDocument().docContent.indexOf("=", current); // make sure there is an equals if ((-1 == equalsAt) || (equalsAt >= inRange.end)) { return result; } // get the name result.startTag.start = current; result.startTag.end = equalsAt - 1; // get the quote char we must match String requiredQuote = getDocument().docContent.substring(equalsAt + 1, equalsAt + 2); // make sure its a valid quote if (('\'' != requiredQuote.charAt(0)) && ('\"' != requiredQuote.charAt(0))) { return result; } // find the next occurance of this quote int nextQuote = getDocument().docContent.indexOf(requiredQuote, equalsAt + 2); // make sure the quote is in a good spot. if ((-1 == nextQuote) || (nextQuote >= inRange.end)) { return result; } result.body.start = equalsAt + 2; result.body.end = nextQuote - 1; result.endTag.start = nextQuote; result.endTag.end = nextQuote; // check if the name matches. if ((null != name) && !name.equals(getDocument().docContent.substring(result.startTag.start, result.startTag.end + 1))) { result.startTag.start = -1; } current = nextQuote + 1; } while ((current < inRange.end) && (!result.isValid())); return result; } /** * {@inheritDoc} */ public String addAttribute(String name, String value) { if (null != uninserted) { throw new IllegalStateException("This element has not been added."); } if (null == name) { throw new IllegalArgumentException("name must not be null"); } if (null == value) { throw new IllegalArgumentException("value must not be null"); } for (int eachChar = name.length() - 1; eachChar >= 0; eachChar--) { if (Character.isWhitespace(name.charAt(eachChar))) { throw new IllegalArgumentException("Attribute names may not contain spaces."); } } if (paranoidConsistencyChecking) { checkConsistency(); } // skip past the name portion int current = loc.startTag.start + 1; while (current <= loc.startTag.end) { char inTagName = getDocument().docContent.charAt(current); if (Character.isWhitespace(inTagName) || ('/' == inTagName) || ('>' == inTagName)) { break; } current++; } // find out if there was a previous value for this name String oldValue = null; tagRange oldAttr = getAttributeLoc(name, new charRange(current, loc.startTag.end)); // choose which kind of quote to use char usingQuote = (-1 != value.indexOf('"')) ? '\'' : '\"'; // make sure we can use it. if (('\'' == usingQuote) && (-1 != value.indexOf('\''))) { throw new IllegalArgumentException("Value contains both \" and \'"); } // build the new attribute string StringBuilder newStuff = new StringBuilder(" "); newStuff.append(name); newStuff.append("="); newStuff.append(usingQuote); newStuff.append(value); newStuff.append(usingQuote); // add it in. if (!oldAttr.isValid()) { // we aren't replacing an existing value getDocument().docContent.insert(current, newStuff.toString()); // move all doc locations which follow this one based on how much we // inserted. getDocument().adjustLocations(current, newStuff.length()); } else { // we are replacing an existing value oldValue = getDocument().docContent.substring(oldAttr.body.start, oldAttr.body.end + 1); getDocument().docContent.delete(oldAttr.body.start, oldAttr.body.end + 1); getDocument().docContent.insert(oldAttr.body.start, value); int delta = value.length() - (oldAttr.body.end - oldAttr.body.start + 1); // move all doc locations which follow this one based on how much we // inserted or deleted. getDocument().adjustLocations(loc.startTag.start + 1, delta); } if (paranoidConsistencyChecking) { checkConsistency(); } return oldValue; } /** * {@inheritDoc} */ public String addAttribute(Attribute newAttrib) { return addAttribute(newAttrib.getName(), newAttrib.getValue()); } /** * {@inheritDoc} */ public Attribute getAttribute(String name) { if (null != uninserted) { throw new IllegalStateException("This element has not been added."); } if (paranoidConsistencyChecking) { checkConsistency(); } // skip past the name portion int current = loc.startTag.start + 1; while (current <= loc.startTag.end) { char inTagName = getDocument().docContent.charAt(current); if (Character.isWhitespace(inTagName) || ('/' == inTagName) || ('>' == inTagName)) { break; } current++; } // find the attribute matching this name tagRange attr = getAttributeLoc(name, new charRange(current, loc.startTag.end)); if (!attr.isValid()) { return null; } // build the object return new Attribute(this, getDocument().docContent.substring(attr.startTag.start, attr.startTag.end + 1) , getDocument().docContent.substring(attr.body.start, attr.body.end + 1)); } protected boolean checkConsistency() { assert loc.isValid(); charRange elementRange = new charRange(loc.startTag.start, loc.endTag.end); assert elementRange.contains(loc.startTag); assert elementRange.contains(loc.body); assert elementRange.contains(loc.endTag); if (null != children) { Iterator<LiteXMLElement> eachChild = children.iterator(); Iterator<LiteXMLElement> nextChilds = children.iterator(); if (nextChilds.hasNext()) { nextChilds.next(); } while (eachChild.hasNext()) { LiteXMLElement aChild = eachChild.next(); assert loc.contains(aChild.loc); if (nextChilds.hasNext()) { LiteXMLElement nextChild = nextChilds.next(); assert aChild.loc.compareTo(nextChild.loc) < 0; } else { assert !eachChild.hasNext(); } aChild.checkConsistency(); } } return true; } /** * The document we are a part of. * * @return The document we are a part of. */ LiteXMLDocument getDocument() { return doc; }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -