📄 xmloutputter.java
字号:
out.write(";"); } /** * This will handle printing of <code>{@link CDATA}</code> text. * * @param cdata <code>CDATA</code> to output. * @param out <code>Writer</code> to use. */ protected void printCDATA(Writer out, CDATA cdata) throws IOException { String str = (currentFormat.mode == Format.TextMode.NORMALIZE) ? cdata.getTextNormalize() : ((currentFormat.mode == Format.TextMode.TRIM) ? cdata.getText().trim() : cdata.getText()); out.write("<![CDATA["); out.write(str); out.write("]]>"); } /** * This will handle printing of <code>{@link Text}</code> strings. * * @param text <code>Text</code> to write. * @param out <code>Writer</code> to use. */ protected void printText(Writer out, Text text) throws IOException { String str = (currentFormat.mode == Format.TextMode.NORMALIZE) ? text.getTextNormalize() : ((currentFormat.mode == Format.TextMode.TRIM) ? text.getText().trim() : text.getText()); out.write(escapeElementEntities(str)); } /** * This will handle printing a string. Escapes the element entities, * trims interior whitespace, etc. if necessary. */ private void printString(Writer out, String str) throws IOException { if (currentFormat.mode == Format.TextMode.NORMALIZE) { str = Text.normalizeString(str); } else if (currentFormat.mode == Format.TextMode.TRIM) { str = str.trim(); } out.write(escapeElementEntities(str)); } /** * This will handle printing of a <code>{@link Element}</code>, * its <code>{@link Attribute}</code>s, and all contained (child) * elements, etc. * * @param element <code>Element</code> to output. * @param out <code>Writer</code> to use. * @param level <code>int</code> level of indention. * @param namespaces <code>List</code> stack of Namespaces in scope. */ protected void printElement(Writer out, Element element, int level, NamespaceStack namespaces) throws IOException { List attributes = element.getAttributes(); List content = element.getContent(); // Check for xml:space and adjust format settings String space = null; if (attributes != null) { space = element.getAttributeValue("space", Namespace.XML_NAMESPACE); } Format previousFormat = currentFormat; if ("default".equals(space)) { currentFormat = userFormat; } else if ("preserve".equals(space)) { currentFormat = preserveFormat; } // Print the beginning of the tag plus attributes and any // necessary namespace declarations out.write("<"); printQualifiedName(out, element); // Mark our namespace starting point int previouslyDeclaredNamespaces = namespaces.size(); // Print the element's namespace, if appropriate printElementNamespace(out, element, namespaces); // Print out additional namespace declarations printAdditionalNamespaces(out, element, namespaces); // Print out attributes if (attributes != null) printAttributes(out, attributes, element, namespaces); // Depending on the settings (newlines, textNormalize, etc), we may // or may not want to print all of the content, so determine the // index of the start of the content we're interested // in based on the current settings. int start = skipLeadingWhite(content, 0); int size = content.size(); if (start >= size) { // Case content is empty or all insignificant whitespace if (currentFormat.expandEmptyElements) { out.write("></"); printQualifiedName(out, element); out.write(">"); } else { out.write(" />"); } } else { out.write(">"); // For a special case where the content is only CDATA // or Text we don't want to indent after the start or // before the end tag. if (nextNonText(content, start) < size) { // Case Mixed Content - normal indentation newline(out); printContentRange(out, content, start, size, level + 1, namespaces); newline(out); indent(out, level); } else { // Case all CDATA or Text - no indentation printTextRange(out, content, start, size); } out.write("</"); printQualifiedName(out, element); out.write(">"); } // remove declared namespaces from stack while (namespaces.size() > previouslyDeclaredNamespaces) { namespaces.pop(); } // Restore our format settings currentFormat = previousFormat; } /** * This will handle printing of content within a given range. * The range to print is specified in typical Java fashion; the * starting index is inclusive, while the ending index is * exclusive. * * @param content <code>List</code> of content to output * @param start index of first content node (inclusive. * @param end index of last content node (exclusive). * @param out <code>Writer</code> to use. * @param level <code>int</code> level of indentation. * @param namespaces <code>List</code> stack of Namespaces in scope. */ private void printContentRange(Writer out, List content, int start, int end, int level, NamespaceStack namespaces) throws IOException { boolean firstNode; // Flag for 1st node in content Object next; // Node we're about to print int first, index; // Indexes into the list of content index = start; while (index < end) { firstNode = (index == start) ? true : false; next = content.get(index); // // Handle consecutive CDATA, Text, and EntityRef nodes all at once // if ((next instanceof Text) || (next instanceof EntityRef)) { first = skipLeadingWhite(content, index); // Set index to next node for loop index = nextNonText(content, first); // If it's not all whitespace - print it! if (first < index) { if (!firstNode) newline(out); indent(out, level); printTextRange(out, content, first, index); } continue; } // // Handle other nodes // if (!firstNode) { newline(out); } indent(out, level); if (next instanceof Comment) { printComment(out, (Comment)next); } else if (next instanceof Element) { printElement(out, (Element)next, level, namespaces); } else if (next instanceof ProcessingInstruction) { printProcessingInstruction(out, (ProcessingInstruction)next); } else { // XXX if we get here then we have a illegal content, for // now we'll just ignore it (probably should throw // a exception) } index++; } /* while */ } /** * This will handle printing of a sequence of <code>{@link CDATA}</code> * or <code>{@link Text}</code> nodes. It is an error to have any other * pass this method any other type of node. * * @param content <code>List</code> of content to output * @param start index of first content node (inclusive). * @param end index of last content node (exclusive). * @param out <code>Writer</code> to use. */ private void printTextRange(Writer out, List content, int start, int end ) throws IOException { String previous; // Previous text printed Object node; // Next node to print String next; // Next text to print previous = null; // Remove leading whitespace-only nodes start = skipLeadingWhite(content, start); int size = content.size(); if (start < size) { // And remove trialing whitespace-only nodes end = skipTrailingWhite(content, end); for (int i = start; i < end; i++) { node = content.get(i); // Get the unmangled version of the text // we are about to print if (node instanceof Text) { next = ((Text) node).getText(); } else if (node instanceof EntityRef) { next = "&" + ((EntityRef) node).getValue() + ";"; } else { throw new IllegalStateException("Should see only " + "CDATA, Text, or EntityRef"); } // This may save a little time if (next == null || "".equals(next)) { continue; } // Determine if we need to pad the output (padding is // only need in trim or normalizing mode) if (previous != null) { // Not 1st node if (currentFormat.mode == Format.TextMode.NORMALIZE || currentFormat.mode == Format.TextMode.TRIM) { if ((endsWithWhite(previous)) || (startsWithWhite(next))) { out.write(" "); } } } // Print the node if (node instanceof CDATA) { printCDATA(out, (CDATA) node); } else if (node instanceof EntityRef) { printEntityRef(out, (EntityRef) node); } else { printString(out, next); } previous = next; } } } /** * This will handle printing of any needed <code>{@link Namespace}</code> * declarations. * * @param ns <code>Namespace</code> to print definition of * @param out <code>Writer</code> to use. */ private void printNamespace(Writer out, Namespace ns, NamespaceStack namespaces) throws IOException { String prefix = ns.getPrefix(); String uri = ns.getURI(); // Already printed namespace decl? if (uri.equals(namespaces.getURI(prefix))) { return; } out.write(" xmlns"); if (!prefix.equals("")) { out.write(":"); out.write(prefix); } out.write("=\""); out.write(escapeAttributeEntities(uri)); out.write("\""); namespaces.push(ns); } /** * This will handle printing of a <code>{@link Attribute}</code> list. * * @param attributes <code>List</code> of Attribute objcts * @param out <code>Writer</code> to use */ protected void printAttributes(Writer out, List attributes, Element parent, NamespaceStack namespaces) throws IOException { // I do not yet handle the case where the same prefix maps to // two different URIs. For attributes on the same element // this is illegal; but as yet we don't throw an exception // if someone tries to do this // Set prefixes = new HashSet(); for (int i = 0; i < attributes.size(); i++) { Attribute attribute = (Attribute) attributes.get(i); Namespace ns = attribute.getNamespace(); if ((ns != Namespace.NO_NAMESPACE) && (ns != Namespace.XML_NAMESPACE)) { printNamespace(out, ns, namespaces); } out.write(" "); printQualifiedName(out, attribute); out.write("="); out.write("\""); out.write(escapeAttributeEntities(attribute.getValue())); out.write("\""); } } private void printElementNamespace(Writer out, Element element, NamespaceStack namespaces) throws IOException { // Add namespace decl only if it's not the XML namespace and it's // not the NO_NAMESPACE with the prefix "" not yet mapped // (we do output xmlns="" if the "" prefix was already used and we // need to reclaim it for the NO_NAMESPACE) Namespace ns = element.getNamespace(); if (ns == Namespace.XML_NAMESPACE) { return; } if ( !((ns == Namespace.NO_NAMESPACE) && (namespaces.getURI("") == null))) { printNamespace(out, ns, namespaces); } } private void printAdditionalNamespaces(Writer out, Element element, NamespaceStack namespaces) throws IOException { List list = element.getAdditionalNamespaces(); if (list != null) { for (int i = 0; i < list.size(); i++) { Namespace additional = (Namespace)list.get(i); printNamespace(out, additional, namespaces); } } } // * * * * * * * * * * Support methods * * * * * * * * * * // * * * * * * * * * * Support methods * * * * * * * * * * /** * This will print a newline only if indent is not null. * * @param out <code>Writer</code> to use */ private void newline(Writer out) throws IOException { if (currentFormat.indent != null) { out.write(currentFormat.lineSeparator); } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -