📄 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 + -