public String processXML(final String input, final boolean applyStyle, final boolean format, final int startLineNo,
                             final List<TextRange> highlights) {
        List<TextRange> remainingHighlights = null;
        if (highlights != null) {
            remainingHighlights = new ArrayList<>(highlights);
        }

        // Reset member variables.
        reset();

        int lineNo = startLineNo;
        int colNo = 0;

        boolean changedElement = false;
        boolean inElement = false;

        output = new StringBuilder(input.length() * 2);
        arr = input.toCharArray();
        for (pos = 0; pos < arr.length; pos++) {
            c = arr[pos];
            colNo++;

            switch (c) {
                case '\n':
                    lineNo++;
                    colNo = 0;

                    // Make sure the element type is content if we aren't in an
                    // element.
                    if (!inElement) {
                        elementType = ElementType.CONTENT;
                    }
                    break;
                case '<':
                    if (!inAttValue) {
                        if (!inElement) {
                            // We are entering an element so reset some variables.
                            changedElement = true;
                            inElement = true;
                            inAttValue = false;
                            doneElementStyle = false;
                            lastCharWasSpace = false;

                            // Get the element type we are entering.
                            elementType = getElementType(pos);
                            elementStartPos = pos;
                            if (elementType == ElementType.COMMENT) {
                                commentState = CommentState.START;
                            }
                        } else if (elementType == ElementType.DOCTYPE) {
                            inEntity = true;
                        }
                    }
                    break;
                case '>':
                    if (!inAttValue) {
                        if (inEntity) {
                            inEntity = false;
                        } else if (inElement) {
                            // If we are in a comment make sure this is the proper
                            // end to a comment.
                            if (elementType == ElementType.COMMENT) {
                                if (back(2) == '-' && back(1) == '-') {
                                    inElement = false;
                                }
                            } else {
                                inElement = false;
                            }
                        }
                    }
                    break;
                default:
                    // Make sure the element type is content if we aren't in an
                    // element.
                    if (!inElement) {
                        elementType = ElementType.CONTENT;
                    }

                    // Do some processing to figure out what the state should be if
                    // we are in a comment.
                    if (elementType == ElementType.COMMENT) {
                        if (commentState == CommentState.START && pos > elementStartPos + 3) {
                            commentState = CommentState.CONTENT;
                        }
                        if (commentState == CommentState.CONTENT
                                && c == '-'
                                && forward(1) == '-'
                                && forward(2) == '>') {
                            commentState = CommentState.END;
                        }
                    }

                    break;
            }

            // See if we want to toggle highlighting.
            if (remainingHighlights != null && remainingHighlights.size() > 0) {
                if (!inHighlight) {
                    // We assume highlights are in appearance order so get the
                    // first from the list.
                    final TextRange highlight = remainingHighlights.get(0);
                    if ((lineNo == highlight.getFrom().getLineNo() && colNo >= highlight.getFrom().getColNo())
                            || lineNo > highlight.getFrom().getLineNo()) {
                        inHighlight = true;
                        changedHighlight = true;
                    }
                } else {
                    // We assume highlights are in appearance order so get the
                    // first from the list.
                    final TextRange highlight = remainingHighlights.get(0);
                    if ((lineNo == highlight.getTo().getLineNo() && colNo >= highlight.getTo().getColNo())
                            || lineNo > highlight.getTo().getLineNo()) {
                        inHighlight = false;
                        changedHighlight = true;

                        // We have finished adding this highlight so remove it
                        // from the list.
                        remainingHighlights.remove(0);
                    }
                }
            }

            // Output indentation if we are formatting this XML.
            if (format && changedElement && elementType != ElementType.CONTENT) {
                if (elementType == ElementType.END) {
                    depth--;
                }

                // If we are looking at a start element and we are already in a
                // start element then output a new line.
                if (lastElementType != null && ((lastElementType != ElementType.END && elementType != ElementType.END)
                        || lastElementType == ElementType.END || lastElementType == ElementType.EMPTY
                        || (lastElementType == ElementType.COMMENT && elementType == ElementType.END))) {
                    escape('\n');

                    // Output an extra new line before comments.
                    if (elementType == ElementType.COMMENT) {
                        escape('\n');
                    }

                    for (int i = 0; i < depth; i++) {
                        write(INDENT);
                    }
                }

                if (elementType == ElementType.START) {
                    depth++;
                }
            }

            // Now format and output the character.
            if (elementType == ElementType.CONTENT) {
                outputStyle(applyStyle, output);

                // Format and output content.
                if (elementType != lastElementType) {
                    if (format && isWhitespace(c) && !preserveWhitespace) {
                        // Ignore this character...
                        // This has the effect of trimming all of the whitespace
                        // off the beginning of some content as we won't set the
                        // lastElementType until we start to get some non
                        // whitespace chars.

                        // If the last element was a start element and the next
                        // element is an end element then we want to preserve
                        // whitespace.
                        if (lastElementType == ElementType.START) {
                            if (nextElementType == null) {
                                nextElementType = getElementType(pos);
                            }

                            if (nextElementType != null && nextElementType == ElementType.END) {
                                preserveWhitespace = true;
                                escape(c);
                                lastElementType = elementType;
                            }
                        }

                    } else {
                        escape(c);
                        lastElementType = elementType;
                    }
                } else {
                    escape(c);
                }
            } else {
                // Trim some space off the preceding content.
                if (format && !preserveWhitespace && lastElementType == ElementType.CONTENT) {
                    trimEndWhitespace(output);
                }

                // Set these variables to stop all whitespace being preserved.
                nextElementType = null;
                preserveWhitespace = false;

                outputStyle(applyStyle, output);

                // Do not format attribute values.
                if (inAttValue) {
                    escape(c);
                    lastCharWasSpace = false;

                } else {
                    // Output the character.
                    if (c == '>') {
                        // Trim spare chars off the end of elements.
                        if (format) {
                            trimEndWhitespace(output);
                        }
                        escape(c);
                        lastCharWasSpace = false;

                    } else if (format && elementType == ElementType.EMPTY && !lastCharWasSpace && c == '/') {
                        // Insert a space before the end of an empty element.
                        escape(' ');
                        escape(c);
                        lastCharWasSpace = false;

                    } else if (format && isWhitespace(c)) {
                        if (elementType == ElementType.COMMENT) {
                            // If this is a new line then output it and add the
                            // necessary indent.
                            if (c == '\n') {
                                escape(c);
                                for (int i = 0; i < depth; i++) {
                                    write(INDENT);
                                }
                            } else if (!lastCharWasSpace) {
                                escape(' ');
                            }
                            lastCharWasSpace = true;

                        } else if (!lastCharWasSpace && forward(1) != '>' && forward(1) != '/' && forward(1) != '='
                                && back(1) != '=') {
                            // Only allow a single space to be added between
                            // attributes.
                            escape(' ');
                            lastCharWasSpace = true;
                        }

                    } else {
                        escape(c);
                        lastCharWasSpace = false;
                    }
                }

                lastElementType = elementType;
            }

            changedElement = false;
        }

        // Close the highlight element if we are in one.
        if (inHighlight) {
            write(Style.HIGHLIGHT.getEnd());
        }

        // Close the last style element if there is one.
        if (lastStyle != null) {
            write(lastStyle.getEnd());
        }

        return output.toString();
    }
Processes some XML and attempts to style and format it depending on the
parameters supplied. The resulting string is HTML containing multiple
&lt;span&gt; elements to style the various XML fragments.

@param input      The input XML to style and format.
@param applyStyle True if this method should add styles to the resultant HTML.
@param format     True if this method should format the XML.
@return An HTML string of the formatted and styled XML.
stroom-core-client-widget/src/main/java/stroom/editor/client/model/XMLStyler.java