Search code examples
javahtml-parsingwell-formednon-well-formed

HTML Well-formedness parser


Heyy guys, I need to determine if a given HTML Document is well formed or not.
I just need a simple implementation using only Java core API classes i.e. no third party stuff like JTIDY or something.

Actually, what is exactly needed is an algorithm that scans a list of TAGS. If it finds an open tag, and the next tag isn't its corresponding close tag, then it should be another open tag which in turn should have its close tag as the next tag, and if not it should be another open tag and then its corresponding close tag next, and the close tags of the previous open tags in reverse order coming one after the other on the list. If the list conforms to this order then it returns true or else false. I've already written methods to convert a tag to a close tag.

Here is the skeleton code of what I've started working on already. Its not too neat, but it should give you guys a basic idea of what I'm trying to do.

public boolean validateHtml(){

    ArrayList<String> tags = fetchTags();
    //fetchTags returns this [<html>, <head>, <title>, </title>, </head>, <body>, <h1>, </h1>, </body>, </html>]

    //I create another ArrayList to store tags that I haven't found its corresponding close tag yet
    ArrayList<String> unclosedTags = new ArrayList<String>();

    String temp;

    for (int i = 0; i < tags.size(); i++) {

        temp = tags.get(i);

        if(!tags.get(i+1).equals(TagOperations.convertToCloseTag(tags.get(i)))){
            unclosedTags.add(tags.get(i));
            if(){

            }

        }else{
            return true;//well formed html
        }
    }

    return true;
}

Solution

  • Two thoughts. First off maybe you could get away with using an XML parser on the html? Potentially easier and vastly less time consuming.

    I havn't put a whole lot of thought into this but to me it sounds like recursion and stack would be the way to go. Something like

    public myClass(String htmlInput)
    {
        openedTags = new Stack<String>();
        this.htmlInput = htmlInput;
    }
    public boolean validate()
    {
        return validate(this.htmlInput);
    }
    private boolean validate(String html)
    {
        boolean result = true;
        String curTag;
        while(htmlLeft)        //worker loop
        {
    
            if(isOneOffTag(curTag))                 //matches <tags />
                continue;
            else if(isOpenTag(curTag))              //matches <tags>
            {
                openedTags.push(curTag);
                if(!validate(innerHtml))
                    return false;
            }
            else if(isCloseTag(curTag))             //matches </tags>
            {
                String lastTag = (String)openedTags.peek();
                if(!tagIsSimiliar(curTag, lastTag))
                    return false;
                openedTags.pop();
            }
        }
    
    
        return result;
    }
    private String nextTag(){return null;}
    private boolean isOpenTag(String tag){ return true;}
    private boolean isCloseTag(String tag){ return true;}
    private boolean isOneOffTag(String tag){ return true;}
    private boolean tagIsSimiliar(String curTag, String lastTag){return true;}
    

    *edit 1: probably should have pushed onto the stack.

    **edit 2: I suppose the issue here would be to determine where when returning solely a boolean you've left off. This would require some kind of pointer so that you know where you've left off. The idea though i believe would still work.