Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  /*
   * Copyright (c) 2012 Vadim Zaslawski, Ontos AG
   * Copyright (c) 2012-2014 Mozilla Foundation
   *
   * Permission is hereby granted, free of charge, to any person obtaining a
   * copy of this software and associated documentation files (the "Software"),
   * to deal in the Software without restriction, including without limitation
   * the rights to use, copy, modify, merge, publish, distribute, sublicense,
   * and/or sell copies of the Software, and to permit persons to whom the
  * Software is furnished to do so, subject to the following conditions:
  *
  * The above copyright notice and this permission notice shall be included in
  * all copies or substantial portions of the Software.
  *
  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  * DEALINGS IN THE SOFTWARE.
  *
  * This code contains comments that are verbatim quotations from the
  * document "HTML: The Living Standard", which has the following copyright
  * and permission notice:
  *
  *   Copyright 2004-2011 Apple Computer, Inc., Mozilla Foundation, and
  *   Opera Software ASA. You are granted a license to use, reproduce and
  *   create derivative works of this document.
  */
 
 package nu.validator.servlet;
 
 
 
 
 public final class OutlineBuildingXMLReaderWrapper implements XMLReader,
         ContentHandler {
 
     private final XMLReader wrappedReader;
 
     private final HttpServletRequest request;
 
     private ContentHandler contentHandler;
 
     public OutlineBuildingXMLReaderWrapper(XMLReader wrappedReader,
             HttpServletRequest request) {
         this. = request;
         this. = wrappedReader;
         this. = wrappedReader.getContentHandler();
         wrappedReader.setContentHandler(this);
     }
 
     private static final int MAX_EXCERPT = 500;
 
     private static final String[] SECTIONING_CONTENT_ELEMENTS = { "article",
             "aside""nav""section" };
 
     private static final String[] SECTIONING_ROOT_ELEMENTS = { "blockquote",
             "body""details""fieldset""figure""td" };
 
     private static final String[] HEADING_CONTENT_ELEMENTS = { "h1""h2",
             "h3""h4""h5""h6""hgroup", };
 
     private Deque<Sectionoutline;
 
     public Deque<SectiongetOutline() {
         return this.;
     }
 
     protected void setOutline(Deque<Sectionoutline) {
         this. = outline;
     }
 
     // an outlinee, a heading content element, or an element with a hidden
     // attribute;
     // during a walk over the nodes of a DOM tree, nodes are identified with
     // their depth and local name
     private class Element {
         // the depth of element in the DOM
         final private int depth;
 
        // the local name of element
        final private String name;
        // whether the element is hidden
        final private boolean hidden;
        // the outline for a sectioning content element or a sectioning root
        // element consists of a list of one or more potentially nested sections
        final private Deque<Sectionoutline = new LinkedList<Section>();
        public Element(int depthString nameboolean hidden) {
            this. = depth;
            this. = name;
            this. = hidden;
        }
        public boolean isHidden() {
            return ;
        }
        public boolean equals(int depthString name) {
            return this. == depth && this..equals(name);
        }

        

Returns:
the outline
        public Deque<SectiongetOutline() {
            return ;
        }

        

Returns:
1-6 for a heading content element MAX_VALUE for an implied heading -1 for no section
        public int getLastSectionHeadingRank() {
            Section section = .peekLast();
            return section != null ? section.getHeadingRank() : -1;
        }
    }
    // a section is a container that corresponds to some nodes in the original
    // DOM tree
    public class Section {
        // the section that contains this section
        private Section parent;
        // an outlinee or a heading content element
        final String elementName;
        // each section can have one heading associated with it
        final private StringBuilder headingTextBuilder = new StringBuilder();
        // we generate an "implied heading" for some sections that lack headings
        private boolean hasImpliedHeading;
        // Generating a special kind of implied heading specifically for
        // the "empty heading" case (e.g., empty <h1></h1> descendant) as
        // opposed to the "no heading" case (no h1-h6 descendants at all)
        // isn't required by the spec, but it's nonetheless useful.
        private boolean hasEmptyHeading;
        // MAX_VALUE for an implied heading, 1-6 for a heading content element
        private int headingRank = .;
        // each section can contain any number of further nested sections
        final public Deque<Sectionsections = new LinkedList<Section>();
        public Section(String elementName) {
            this. = elementName;
        }

        

Returns:
the parent section
        public Section getParent() {
            return ;
        }

        

Returns:
the lement name
        public String getElementName() {
            return ;
        }

        

Parameters:
parent the parent section to set
        public void setParent(Section parent) {
            this. = parent;
        }

        

Returns:
the heading text builder
        public StringBuilder getHeadingTextBuilder() {
            return ;
        }

        

Returns:
the heading rank
        public int getHeadingRank() {
            return ;
        }

        

Returns:
the sections
        public Deque<SectiongetSections() {
            return ;
        }
        public void setHeadingRank(int headingRank) {
            this. = headingRank;
        }
        public boolean hasHeading() {
            return  < 7 || ;
        }
        public void createImpliedHeading() {
             = true;
        }
        public void createEmptyHeading() {
             = true;
        }
        public boolean hasEmptyHeading() {
            return ;
        }
    }
    // tracks the depth of walk through the DOM
    private int currentWalkDepth;
    // holds the element whose outline is being created;
    // a sectioning content element or a sectioning root element
    private Element currentOutlinee;
    // A stack (not defined in the spec) to hold all open elements. We just
    // use this stack for the purpose of checking whether there are any
    // open elements at all with a "hidden" attribute -- including elements
    // that may be descendants of heading-content elements (which per the
    // spec never end up on the outline stack).
    private Deque<ElementelementStack = new LinkedList<Element>();
    private boolean inHiddenSubtree() {
        for (Element element : ) {
            if (element.isHidden()) {
                return true;
            }
        }
        return false;
    }
    // A stack, defined in the spec, to which we only add open
    // heading-content elements and elements with a "hidden" attribute that
    // are ancestors to heading-content elements.
    private Deque<ElementoutlineStack = new LinkedList<Element>();
    // The top of the outline stack defined in the spec is always either a
    // heading content element or an element with a hidden attribute.
    private boolean inHeadingContentOrHiddenElement;
    private boolean needHeading;
    private boolean skipHeading;
    // holds a pointer to a section, so that elements in the DOM can all be
    // associated with a section
    private Section currentSection;
    private boolean isWalkOver;
    private static final Pattern excerptPattern = Pattern.compile("\\W*\\S*$");
    private static final Pattern whitespacePattern = Pattern.compile("\\s+");
    /*
     * Returns the string excerpt.
     */
    private String excerpt(String strint maxLength) {
        return str.length() > maxLength ? .matcher(
                str.substring(0, maxLength)).replaceFirst("&hellip;") : str;
    }

    
    public void characters(char[] chint startint length)
            throws SAXException {
        if ( == null) {
            return;
        }
        if () {
            .characters(chstartlength);
            return;
        }
        if ( && !inHiddenSubtree()) {
            .getHeadingTextBuilder().append(chstartlength);
        }
        .characters(chstartlength);
    }

    
    public void endElement(String uriString localNameString qName)
            throws SAXException {
        if ( == null) {
            return;
        }
        .pop();
        if ("hgroup".equals(localName)) {
             = false;
             = false;
        }
        if () {
            .endElement(urilocalNameqName);
            return;
        }
        int depth = --;
        if () {
            // When exiting an element, if that element is the element at the
            // top of the stack
            // Note: The element being exited is a heading content element or an
            // element with a hidden attribute.
            Element topElement = .peek();
            assert topElement != null;
            if (topElement.equals(depthlocalName)) {
                // Pop that element from the stack.
                .pop();
                 = false;
                if ( != null) {
                    StringBuilder headingTextBuilder = .getHeadingTextBuilder();
                    String heading = excerpt(
                            .matcher(headingTextBuilder).replaceAll(
                                    " ").trim(), );
                    headingTextBuilder.setLength(0);
                    if (heading.length() > 0) {
                        headingTextBuilder.append(heading);
                    } else {
                        .createEmptyHeading();
                    }
                }
            }
            // If the top of the stack is a heading content element or an
            // element with a hidden attribute
            // Do nothing.
            .endElement(urilocalNameqName);
            return;
        }
        if (Arrays.binarySearch(localName) > -1) {
            // When exiting a sectioning content element, if the stack is not
            // empty
            if (!.isEmpty()) {
                // If the current section has no heading,
                if ( != null && !.hasHeading()) {
                    // create an implied heading and let that be the heading for
                    // the current section.
                    .createImpliedHeading();
                }
                Element exitedSectioningContentElement = ;
                assert exitedSectioningContentElement != null;
                // Pop the top element from the stack, and let the current
                // outlinee be that element.
                 = .pop();
                // Let current section be the last section in the outline of the
                // current outlinee element.
                 = .getOutline().peekLast();
                assert  != null;
                // Append the outline of the sectioning content element being
                // exited to the current section.
                // (This does not change which section is the last section in
                // the outline.)
                for (Section section : exitedSectioningContentElement.outline) {
                    section.setParent();
                    ..add(section);
                }
            }
        } else if (Arrays.binarySearch(localName) > -1) {
            // When exiting a sectioning root element, if the stack is not empty
            if (!.isEmpty()) {
                // Run these steps:
                // If the current section has no heading,
                if ( != null && !.hasHeading()) {
                    // create an implied heading and let that be the heading for
                    // the current section.
                    .createImpliedHeading();
                }
                // Pop the top element from the stack, and let the current
                // outlinee be that element.
                 = .pop();
                // Let current section be the last section in the outline of the
                // current outlinee element.
                 = .getOutline().peekLast();
                // Finding the deepest child:
                // If current section has no child sections, stop these steps.
                while (!..isEmpty())
                    // Let current section be the last child section of the
                    // current current section.
                     = ..peekLast();
                // Go back to the substep labeled finding the deepest child.
            }
        } else {
            // neither a sectioning content element nor a sectioning root
            // element
            .endElement(urilocalNameqName);
            return;
        }
        // When exiting a sectioning content element or a sectioning root
        // element
        // Note: The current outlinee is the element being exited, and
        // it is the sectioning content element or a sectioning root element at
        // the root of the subtree for which an outline is being generated.
        // If the current section has no heading,
        if ( != null && !.hasHeading()) {
            // create an implied heading and let that be the heading for the
            // current section.
            .createImpliedHeading();
        }
        // Skip to the next step in the overall set of steps.
        // (The walk is over.)
        // / isWalkOver = true;
        .endElement(urilocalNameqName);
    }

    
    public void startDocument() throws SAXException {
        if ( == null) {
            return;
        }
        .startDocument();
    }

    
    public void startElement(String uriString localNameString qName,
            Attributes attsthrows SAXException {
        if ( == null) {
            return;
        }
        if () {
            .startElement(urilocalNameqNameatts);
            return;
        }
        ++;
        boolean hidden = atts.getIndex("""hidden") >= 0;
        .push(new Element(localNamehidden));
        // If the top of the stack is a heading content element or an element
        // with a hidden attribute
        if () {
            if (!inHiddenSubtree() && "img".equals(localName)
                    && atts.getIndex("""alt") >= 0) {
                .getHeadingTextBuilder().append(
                        atts.getValue("""alt"));
            }
            // Do nothing.
            .startElement(urilocalNameqNameatts);
            return;
        }
        // When entering an element with a hidden attribute
        if (hidden) {
            // Push the element being entered onto the stack. (This causes the
            // algorithm to skip that element and any descendants of the
            // element.)
            .push(new Element(localNamehidden));
             = true;
            .startElement(urilocalNameqNameatts);
            return;
        }
        // When entering a sectioning content element or a sectioning root
        // element
        if (Arrays.binarySearch(localName) > -1
                || Arrays.binarySearch(localName) > -1) {
            if ( != null) {
                // If current outlinee is not null, and the current section has
                // no heading,
                // create an implied heading and let that be the heading for the
                // current section.
                if ( != null && !.hasHeading()) {
                    .createImpliedHeading();
                }
                // If current outlinee is not null, push current outlinee onto
                // the stack.
                .push();
            }
            // Let current outlinee be the element that is being entered.
             = new Element(localNamehidden);
            // Let current section be a newly created section for the current
            // outlinee element.
            // Associate current outlinee with current section.
             = new Section(localName);
            // Let there be a new outline for the new current outlinee,
            // initialized with just the new current section as the only section
            // in the outline.
            .getOutline().add();
            .startElement(urilocalNameqNameatts);
            return;
        }
        // When entering a heading content element
        // Note: Recall that h1 has the highest rank, and h6 has the lowest
        // rank.
        if (Arrays.binarySearch(localName) > -1
                &&  != null) {
            if ("hgroup".equals(localName)) {
                 = true;
                 = false;
                .startElement(urilocalNameqNameatts);
                return;
            } else if () {
                .startElement(urilocalNameqNameatts);
                return;
            } else if () {
                 = true;
                 = false;
            }
            int rank = localName.charAt(1) - '0';
            // If the current section has no heading,
            // let the element being entered be the heading for the current
            // section.
            if ( != null && !.hasHeading()) {
                .setHeadingRank(rank);
            }
            // Otherwise, if the element being entered has a rank equal to
            // or higher than the heading of the last section of the
            // outline of the current outlinee, or if the heading of the
            // last section of the outline of the current outlinee is an
            // implied heading,
            else if (rank <= .getLastSectionHeadingRank()) {
                // then create a new section and append it to the outline
                // of the current outlinee element, so that this new
                // section is the new last section of that outline.
                // Let current section be that new section.
                 = new Section(localName);
                .getOutline().add();
                // Let the element being entered be the new heading for the
                // current section.
                .setHeadingRank(rank);
            }
            // Otherwise, run these substeps:
            else {
                // Let candidate section be current section.
                Section candidateSection = ;
                // Heading loop:
                while (candidateSection != null) {
                    // If the element being entered has a rank lower than the
                    // rank of the heading of the candidate section,
                    if (rank > candidateSection.getHeadingRank()) {
                        // then create a new section, and append it to candidate
                        // section.
                        // (This does not change which section is the last
                        // section in the outline.)
                        // Let current section be this new section.
                         = new Section(localName);
                        .setParent(candidateSection);
                        candidateSection.getSections().add();
                        // Let the element being entered be the new heading for
                        // the current section.
                        .setHeadingRank(rank);
                        // Abort these substeps.
                        break;
                    }
                    // Let new candidate section be the section that contains
                    // candidate section in the outline of current outlinee.
                    // Let candidate section be new candidate section.
                    candidateSection = candidateSection.getParent();
                    // Return to the step labeled heading loop.
                }
            }
            // Push the element being entered onto the stack.
            // (This causes the algorithm to skip any descendants of the
            // element.)
            .push(new Element(localNamehidden));
             = true;
        }
        .startElement(urilocalNameqNameatts);
    }

    
    public void setDocumentLocator(Locator locator) {
        if ( == null) {
            return;
        }
        .setDocumentLocator(locator);
    }
    public ContentHandler getContentHandler() {
        return ;
    }

    
    public void endDocument() throws SAXException {
        if ( == null) {
            return;
        }
        if ( != null) {
            .setAttribute(
                    "http://validator.nu/properties/document-outline",
                    (Deque<Section>) .);
            setOutline(.);
        }
        .endDocument();
    }

    
    public void endPrefixMapping(String prefixthrows SAXException {
        if ( == null) {
            return;
        }
        .endPrefixMapping(prefix);
    }

    
    public void ignorableWhitespace(char[] chint startint length)
            throws SAXException {
        if ( == null) {
            return;
        }
        .ignorableWhitespace(chstartlength);
    }

    
    public void processingInstruction(String targetString data)
            throws SAXException {
        if ( == null) {
            return;
        }
        .processingInstruction(targetdata);
    }

    
    public void skippedEntity(String namethrows SAXException {
        if ( == null) {
            return;
        }
        .skippedEntity(name);
    }

    
    public void startPrefixMapping(String prefixString uri)
            throws SAXException {
        if ( == null) {
            return;
        }
        .startPrefixMapping(prefixuri);
    }

    
    public DTDHandler getDTDHandler() {
        return .getDTDHandler();
    }

    
    public EntityResolver getEntityResolver() {
        return .getEntityResolver();
    }

    
    public ErrorHandler getErrorHandler() {
        return .getErrorHandler();
    }

    
    public boolean getFeature(String namethrows SAXNotRecognizedException,
            SAXNotSupportedException {
        return .getFeature(name);
    }

    
    public Object getProperty(String namethrows SAXNotRecognizedException,
            SAXNotSupportedException {
        return .getProperty(name);
    }

    
    public void parse(InputSource inputthrows IOExceptionSAXException {
        .parse(input);
    }

    
    public void parse(String systemIdthrows IOExceptionSAXException {
        .parse(systemId);
    }

    
    public void setContentHandler(ContentHandler handler) {
         = handler;
    }

    
    public void setDTDHandler(DTDHandler handler) {
        .setDTDHandler(handler);
    }

    
    public void setEntityResolver(EntityResolver resolver) {
        .setEntityResolver(resolver);
    }

    
    public void setErrorHandler(ErrorHandler handler) {
        .setErrorHandler(handler);
    }

    
    public void setFeature(String nameboolean value)
            throws SAXNotRecognizedExceptionSAXNotSupportedException {
        .setFeature(namevalue);
    }

    
    public void setProperty(String nameObject value)
            throws SAXNotRecognizedExceptionSAXNotSupportedException {
        .setProperty(namevalue);
    }
New to GrepCode? Check out our FAQ X