xlawrence    2005/07/08 16:50:16 CEST

  Added files:
    core/src/java/org/jahia/services/htmlparser WAIValidator.java 
    core/src/test/src/java/org/jahia/services/htmlparser 
                                                         WAIValidatorTest.java 
  Log:
  First version of the WAI validator (bronze level)
  
  Revision  Changes    Path
  1.1       +807 -0    
jahia/core/src/java/org/jahia/services/htmlparser/WAIValidator.java (new)
http://jahia.mine.nu:8080/cgi-bin/cvsweb.cgi/jahia/core/src/java/org/jahia/services/htmlparser/WAIValidator.java?rev=1.1&content-type=text/plain
  1.1       +252 -0    
jahia/core/src/test/src/java/org/jahia/services/htmlparser/WAIValidatorTest.java
 (new)
http://jahia.mine.nu:8080/cgi-bin/cvsweb.cgi/jahia/core/src/test/src/java/org/jahia/services/htmlparser/WAIValidatorTest.java?rev=1.1&content-type=text/plain
  
  
  
  Index: WAIValidator.java
  ====================================================================
  /*
   *                                   ____.
   *                       __/\ ______|    |__/\.     _______
   *            __   .____|    |       \   |    +----+       \
   *    _______|  /--|    |    |    -   \  _    |    :    -   \_________
   *   \\______: :---|    :    :           |    :    |         \________>
   *           |__\---\_____________:______:    :____|____:_____\
   *                                      /_____|
   *
   *              . . . i n   j a h i a   w e   t r u s t . . .
   *
   *
   *
   * ----- BEGIN LICENSE BLOCK -----
   * Version: JCSL 1.0
   *
   * The contents of this file are subject to the Jahia Community Source License
   * 1.0 or later (the "License"); you may not use this file except in
   * compliance with the License. You may obtain a copy of the License at
   * http://www.jahia.org/license
   *
   * Software distributed under the License is distributed on an "AS IS" basis,
   * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
   * for the rights, obligations and limitations governing use of the contents
   * of the file. The Original and Upgraded Code is the Jahia CMS and Portal
   * Server. The developer of the Original and Upgraded Code is JAHIA Ltd. JAHIA
   * Ltd. owns the copyrights in the portions it created. All Rights Reserved.
   *
   * The Shared Modifications are Jahia View Helper.
   *
   * The Developer of the Shared Modifications is Jahia Solution Sàrl.
   * Portions created by the Initial Developer are Copyright (C) 2002 by the
   * Initial Developer. All Rights Reserved.
   *
   * ----- END LICENSE BLOCK -----
   */
  
  package org.jahia.services.htmlparser;
  
  import org.jahia.engines.validation.EngineValidationHelper;
  import org.jahia.engines.validation.ValidationError;
  
  import org.jahia.utils.JahiaTools;
  
  import org.cyberneko.html.parsers.DOMFragmentParser;
  
  import org.w3c.dom.Node;
  import org.w3c.dom.DocumentFragment;
  import org.w3c.dom.DOMException;
  
  import org.w3c.dom.html.HTMLDocument;
  import org.w3c.dom.html.HTMLBodyElement;
  import org.w3c.dom.html.HTMLAnchorElement;
  import org.w3c.dom.html.HTMLImageElement;
  import org.w3c.dom.html.HTMLAreaElement;
  import org.w3c.dom.html.HTMLFormElement;
  import org.w3c.dom.html.HTMLTableElement;
  import org.w3c.dom.html.HTMLFrameElement;
  
  import org.apache.html.dom.HTMLDocumentImpl;
  import org.apache.html.dom.HTMLAnchorElementImpl;
  import org.apache.html.dom.HTMLImageElementImpl;
  import org.apache.html.dom.HTMLAreaElementImpl;
  import org.apache.html.dom.HTMLFormElementImpl;
  import org.apache.html.dom.HTMLTableElementImpl;
  import org.apache.html.dom.HTMLFrameElementImpl;
  import org.apache.html.dom.HTMLTableCaptionElementImpl;
  import org.apache.html.dom.HTMLTableRowElementImpl;
  import org.apache.html.dom.HTMLLabelElementImpl;
  import org.apache.html.dom.HTMLInputElementImpl;
  
  import java.io.File;
  import java.io.FileOutputStream;
  import java.io.IOException;
  
  import java.util.List;
  import java.util.ArrayList;
  import java.util.HashMap;
  
  /**
   * This class is used to validate an HTML fragment against the WAI (Accessiweb
   * Section 508) rules. All the 55 "Bronze" criterias can be found here: <br/>
   * <a 
href="http://www.accessiweb.org/fr/Label%5FAccessibilite/criteres%5Faccessiweb/55%5Faccessiweb%5Fbronze/";
   *  target="_blank">Accessiweb</a>
   *
   * @author Xavier Lawrence
   */
  public class WAIValidator {
      
      private static final org.apache.log4j.Logger logger =
              org.apache.log4j.Logger.getLogger(WAIValidator.class);
      
      protected final DOMFragmentParser parser = new DOMFragmentParser();
      
      private boolean isDataTable = true;
      private int formLevel;
      
      protected final HashMap linkToDest = new HashMap();
      
      /**
       * Validates a HTML fragment represented as a String.
       * @param inputHTML The html fragment
       *
       * @return EngineValidationHelper containing the validation errors, in 
case
       *         of no errors, an empty EngineValidationHelper is returned.
       *
       * @throws IOException If problems occured with the Temporary file
       *                     used to store the input HTML fragment.
       */
      public EngineValidationHelper validate( final String inputHTML )
      throws IOException {
          final EngineValidationHelper evh = new EngineValidationHelper();
          final HTMLDocument document = new HTMLDocumentImpl();
          final DocumentFragment fragment = document.createDocumentFragment();
          final File tempFile = File.createTempFile("tmp", ".html");
          
          try {
              final FileOutputStream fos = new FileOutputStream(tempFile);
              fos.write(inputHTML.getBytes());
              fos.flush();
              fos.close();
              
              parser.parse(tempFile.getAbsolutePath(), fragment);
              
          } catch (Exception e) {
              logger.error("Error parsing HTML fragment !", e);
              final ValidationError error = new 
ValidationError(WAIValidator.class,
                      "Unable to parse HTML fragment: " + e.getMessage());
              evh.addError(error);
              return evh;
              
          } finally {
              if (tempFile != null) {
                  tempFile.delete();
              }
          }
          
          // The DOMFragmentParser generates a HTML and a BODY element which are
          // of no interest for us. We select the HTMLBodyElement which will 
then
          // be consumed in the validateHtml method. It is the starting root 
element
          // of the HTML fragment.
          linkToDest.clear();
          final HTMLBodyElement node = 
(HTMLBodyElement)fragment.getFirstChild().
                  getFirstChild();
          
          final List errors = validateHtml(node);
          for (int i=0; i<errors.size(); i++) {
              evh.addError((ValidationError)errors.get(i));
          }
          
          return evh;
      }
      
      /**
       * Validates an HTML fragment starting from the body element.
       *
       * @param node The HTMLBodyElement implementation node.
       * @return A list of ValidationError Objects, the list will be emtpy in 
case
       *         no errors occured.
       */
      protected List validateHtml( final HTMLBodyElement node ) {
          final List errors = new ArrayList();
          try {
              validateHtml(node, errors, 0);
              
          } catch (DOMException de) {
              logger.error("Cannot validate html: "+ de.getMessage(), de);
              final ValidationError ve = new ValidationError(this,
                      "Cannot validate html: "+ de.getMessage());
              errors.add(ve);
          }
          
          return errors;
      }
      
      /**
       * Recursive method that goes through all the nodes of the parsed HTML 
tree.
       *
       * @param node The current Node being processed.
       * @param errors The List of errors reported so far
       * @param level The level in the Tree of the node being processed
       *
       * @throws DOMException If something goes wrong.
       */
      private void validateHtml( final Node node, final List errors,
              int level) throws DOMException {
          Node child;
          if (processNode(node, errors, level)) {
              child = node.getFirstChild();
              level++;
          } else {
              return;
          }
          while (child != null) {
              validateHtml(child, errors, level);
              child = child.getNextSibling();
          }
      }
      
      /**
       * Method that tests the class of the given node and invokes the proper
       * validation method.
       *
       * @param node The current Node
       * @param errors The List of reported errors so far
       * @param level The level of the Node in the DOM tree.
       *
       * @return True if the next Node to process is a Child Node, False if the
       *              next Node has to be a Sibling Node.
       *
       * @throws DOMException If something goes wrong.
       */
      private boolean processNode( final Node node, final List errors,
              final int level) throws DOMException {
          resetIsDataTable(level);
          final Class childClass = node.getClass();
          final ValidationError err;
          if (childClass == HTMLAnchorElementImpl.class) {
              err = validateLink((HTMLAnchorElement)node);
              
          } else if (childClass == HTMLImageElementImpl.class) {
              err = validateImage((HTMLImageElement)node);
              
          } else if (childClass == HTMLAreaElementImpl.class) {
              err = validateAreaShape((HTMLAreaElement)node);
              
          } else if (childClass == HTMLFormElementImpl.class) {
              errors.addAll(validateForm((HTMLFormElement)node,
                      level));
              return false;
              
          } else if (childClass == HTMLTableElementImpl.class) {
              errors.addAll(validateTable((HTMLTableElement)node));
              return false;
              
          } else if (childClass == HTMLFrameElementImpl.class) {
              err = validateFrame((HTMLFrameElement)node);
              
          } else {
              logger.debug("Ignoring node of type: " + childClass);
              return true;
          }
          
          if (err != null) { errors.add(err); }
          return true;
      }
      
      /**
       * Sets the isDataTable boolean to false and stores the level of the Node
       * which invoked this method. The variable is used to distinguish data 
Tables,
       * which need to be validated, against formatting or form tables which 
don't.
       *
       * @param level The level of the Form tag being processed.
       */
      protected void setIsDataTable(int level) {
          if (! isDataTable) {
              throw new IllegalStateException("isDataTable allready set");
          }
          formLevel = level;
          isDataTable = false;
      }
      
      /**
       * If the level given in parameter is equal to the formLevel which
       * previously set the isDataTable to false, then we have finished
       * processing the form and we can set the variable back to true.
       *
       * @param level The level of the tag being processed.
       */
      protected void resetIsDataTable(int level) {
          if (level == formLevel) {
              isDataTable = true;
          }
      }
      
      /**
       * Validates a link Element.
       *
       * @param node The HTMLAnchorElement.
       * @return ValidationError or null if no error occured.
       */
      protected ValidationError validateLink( final HTMLAnchorElement node )
      throws DOMException {
          logger.info("validateLink");
          
          // Criteria 6.1
          final String linkValue = JahiaTools.text2XMLEntityRef(
                  node.getFirstChild().getNodeValue(), 1);
          final int length = linkValue.length();
          if (length > 80) {
              final ValidationError ve = new ValidationError(this,
                      "Link value should not be longer than 80 characters. 
Length = " +
                      length);
              return ve;
          }
          
          // Criteria 6.3
          final Node title = node.getAttributes().getNamedItem("title");
          if (title == null) {
              final ValidationError ve = new ValidationError(this,
                      "Missing 'title' attribute for 'hyperlink' element");
              return ve;
          }
          
          // Criteria 6.3 bis
          final String titleValue = JahiaTools.text2XMLEntityRef(
                  title.getNodeValue(), 1);
          final int length2 = titleValue.length();
          if (length2 > 80) {
              final ValidationError ve = new ValidationError(this,
                      "Attribute 'title' should not be longer than 80 
characters. Length = " +
                      length2);
              return ve;
          }
          
          // Criteria 6.5
          final String hrefValue = 
node.getAttributes().getNamedItem("href").getNodeValue();
          if (linkToDest.containsKey(linkValue)) {
              final String dest = (String)linkToDest.get(linkValue);
              
              if (! hrefValue.equals(dest)) {
                  final ValidationError ve = new ValidationError(this,
                          "All same link values should point to the same 
destination");
                  return ve;
              }
              
          } else {
              linkToDest.put(linkValue, hrefValue);
          }
          
          return null;
      }
      
      /**
       * Validates an Img Element.
       *
       * @param node The HTMLImageElement.
       * @return ValidationError or null if no error occured.
       */
      protected ValidationError validateImage( final HTMLImageElement node ) {
          logger.info("validateImage");
          
          // Criteria 1.1
          final Node alt = node.getAttributes().getNamedItem("alt");
          if (alt == null) {
              final Node src = node.getAttributes().getNamedItem("src");
              final String srcText;
              
              if (src == null) {
                  srcText = "n/a";
              } else {
                  srcText = src.getNodeValue();
              }
              
              final ValidationError ve = new ValidationError(this,
                      "Missing 'alt' attribute for image " + srcText);
              return ve;
          }
          
          // Criteria 1.4
          final String altValue = 
JahiaTools.text2XMLEntityRef(alt.getNodeValue(), 1);
          final int length = altValue.length();
          if (length > 60) {
              final ValidationError ve = new ValidationError(this,
                      "Attribute 'alt' should not be longer than 60 characters. 
Length = " +
                      length + ". Use attribute 'longdesc' if you want a longer 
description");
              return ve;
          }
          
          return null;
      }
      
      /**
       * Validates an Area Element.
       *
       * @param node The HTMLAreaElement.
       * @return ValidationError or null if no error occured.
       */
      protected ValidationError validateAreaShape( final HTMLAreaElement node ) 
{
          logger.info("validateAreaShape");
          
          // Criteria 1.1
          if (node.getAttributes().getNamedItem("shape") != null) {
              
              final Node alt = node.getAttributes().getNamedItem("alt");
              if (alt == null) {
                  final ValidationError ve = new ValidationError(this,
                          "Missing 'alt' attribute for 'area' element");
                  return ve;
              }
          }
          
          return null;
      }
      
      /**
       * Validates a Table Element.
       *
       * @param node The HTMLFormElement.
       * @return A List of ValidationError Objects.
       */
      protected List validateTable( final HTMLTableElement node ) {
          logger.info("validateTable");
          
          final List errors = new ArrayList();
          
          if (! isDataTable) { return errors; }
          
          /*
           *
           <TABLE border="1"
                  summary="This table charts the number of cups
                  of coffee consumed by each senator, the type
                  of coffee (decaf or regular), and whether
                  taken with sugar.">
              <CAPTION>Cups of coffee consumed by each senator</CAPTION>
              <TR>
                  <TH id="t1">Name</TH>
                  <TH id="t2">Cups</TH>
                  <TH id="t3" abbr="Type">Type of Coffee</TH>
                  <TH id="t4">Sugar?</TH>
              <TR>
                  <TD headers="t1">T. Sexton</TD>
                  <TD headers="t2">10</TD>
                  <TD headers="t3">Espresso</TD>
                  <TD headers="t4">No</TD>
              <TR>
                  <TD headers="t1">J. Dinnen</TD>
                  <TD headers="t2">5</TD>
                  <TD headers="t3">Decaf</TD>
                  <TD headers="t4">Yes</TD>
          </TABLE>
           *
           *
          <TABLE border="1"
                  summary="This table charts the number of cups
                  of coffee consumed by each senator, the type
                  of coffee (decaf or regular), and whether
                  taken with sugar.">
              <CAPTION>Cups of coffee consumed by each senator</CAPTION>
              <TR>
                  <TH scope="col">Name</TH>
                  <TH scope="col">Cups</TH>
                  <TH scope="col" abbr="Type">Type of Coffee</TH>
                  <TH scope="col">Sugar?</TH>
              <TR>
                  <TD>T. Sexton</TD>
                  <TD>10</TD>
                  <TD>Espresso</TD>
                  <TD>No</TD>
              <TR>
                  <TD>J. Dinnen</TD>
                  <TD>5</TD>
                  <TD>Decaf</TD>
                  <TD>Yes</TD>
          </TABLE>
           *
           */
          
          // Criteria 5.1
          final Node summary = node.getAttributes().getNamedItem("summary");
          if (summary == null) {
              final ValidationError ve = new ValidationError(this,
                      "Missing 'summary' attribute for 'table' element");
              errors.add(ve);
              return errors;
          }
          
          Node caption = node.getFirstChild();
          while (caption != null &&
                  caption.getClass() != HTMLTableCaptionElementImpl.class) {
              caption = caption.getNextSibling();
          }
          
          // Criteria 5.2
          if (caption == null) {
              final ValidationError ve = new ValidationError(this,
                      "Missing 'caption' element for 'table' element");
              errors.add(ve);
              return errors;
          }
          
          // Criteria 5.3
          Node header = node.getFirstChild();
          while (header != null &&
                  header.getClass() != HTMLTableRowElementImpl.class) {
              header = header.getNextSibling();
          }
          
          header = node.getFirstChild();
          
          // get the first row
          while (! "tr".equals(header.getNodeName().toLowerCase())) {
              header = header.getNextSibling();
          }
          
          header = header.getFirstChild();
          
          final ArrayList ids = new ArrayList();
          int scopes = 0;
          
          while (header != null) {
              if (! "th".equals(header.getNodeName().toLowerCase())) {
                  final ValidationError ve = new ValidationError(this,
                          "The first row of a 'table' element should contain 
'th' elements only");
                  errors.add(ve);
                  return errors;
              }
              
              final Node scope = header.getAttributes().getNamedItem("scope");
              final Node id = header.getAttributes().getNamedItem("id");
              
              if ((scope == null && id == null) || (scope != null && id != 
null)) {
                  final ValidationError ve = new ValidationError(this,
                          "'th' elements should have an attribute 'scope', set 
to 'col', OR an 'id' attribute");
                  errors.add(ve);
                  return errors;
              }
              
              if (id == null) {
                  if (! "col".equals(scope.getNodeValue().toLowerCase())) {
                      final ValidationError ve = new ValidationError(this,
                              "The 'th' elements of the first row of the table 
should have a 'col' scope");
                      errors.add(ve);
                      return errors;
                  }
                  scopes++;
                  
              } else {
                  final String value = id.getNodeValue();
                  if (! ids.contains(value)) {
                      ids.add(value);
                  }
              }
              
              header = header.getNextSibling();
          }
          
          if (scopes > 0 && ids.size() > 0) {
              final ValidationError ve = new ValidationError(this,
                      "The 'th' elements of the first row of the table should 
all use the same attribute");
              errors.add(ve);
              return errors;
          }
          
          // check the rest of the table cells
          if (ids.size() > 0) {
              final List headers = new ArrayList();
              processTable(node, headers, errors);
              
              final ArrayList ids2 = (ArrayList)ids.clone();
              for (int i=0; i<ids2.size(); i++) {
                  final String value = (String)ids2.get(i);
                  if (headers.contains(value)) {
                      headers.remove(value);
                      ids.remove(value);
                  }
              }
              
              if (headers.size() > 0) {
                  for (int i=0; i<headers.size(); i++) {
                      final ValidationError ve = new ValidationError(this,
                              "Attribute 'header' (" + headers.get(i) + ") has 
no corresponding 'id'");
                      errors.add(ve);
                  }
              }
          }
          
          return errors;
      }
      
      /**
       * Recursive method to process a Table element and all its children
       *
       * @param node The current node of the Table.
       * @param headers The current list of 'headers' attributes (present in 
tds)
       * @param errors The current list of errors
       */
      protected void processTable( final Node node, final List headers,
              final List errors ){
          
          // Criteria 5.4
          if ( "td".equals(node.getNodeName().toLowerCase())) {
              
              final Node header = node.getAttributes().getNamedItem("headers");
              if (header == null) {
                  final ValidationError ve = new ValidationError(this,
                          "Missing 'headers' attribute for 'td' element");
                  errors.add(ve);
                  
              } else {
                  final String value = header.getNodeValue();
                  if (! headers.contains(value)) {
                      headers.add(value);
                  }
              }
          }
          
          Node child = node.getFirstChild();
          while (child != null) {
              processTable(child, headers, errors);
              child = child.getNextSibling();
          }
      }
      
      /**
       * Validates a Form Element.
       *
       * @param node The HTMLFormElement.
       * @param level The level of the root form node in relation to the top 
root
       *              node of the html fragment.
       * @return A List of ValidationError Objects.
       */
      protected List validateForm( final HTMLFormElement node,
              final int level) {
          logger.info("validateForm");
          setIsDataTable(level);
          
          final ArrayList fors = new ArrayList();
          final ArrayList ids = new ArrayList();
          final ArrayList errors = new ArrayList();
          
          /*
           <FORM action="..." method="post">
              <LABEL for="firstname">First name: </LABEL>
              <INPUT type="text" id="firstname">
           */
          processForm(node, fors, ids, errors);
          
          final ArrayList fors2 = (ArrayList)fors.clone();
          
          for (int i=0; i<fors2.size(); i++) {
              final String value = (String)fors2.get(i);
              if (ids.contains(value)) {
                  fors.remove(value);
                  ids.remove(value);
              }
          }
          
          if (fors.size() > 0) {
              for (int i=0; i<fors.size(); i++) {
                  final ValidationError ve = new ValidationError(this,
                          "They are no 'id' attribute in any 'input' element 
for attribute 'for' (" +
                          fors.get(i) + "). Check all your 'label' elements in 
the 'form'");
                  errors.add(ve);
              }
          }
          
          if (ids.size() > 0) {
              for (int i=0; i<ids.size(); i++) {
                  final ValidationError ve = new ValidationError(this,
                          "All text 'input' elements should have a 
corresponding 'label' element." +
                          "'Input' element with id (" + ids.get(i) + ") has no 
label");
                  errors.add(ve);
              }
          }
          
          return errors;
      }
      
      /**
       * Recursive method to process a Form element and all its children
       *
       * @param node The current node of the Form.
       * @param fors The current list of 'for' attributes (present in labels)
       * @param ids The current list of 'id' attributes (present in text inputs)
       * @param errors The current list of errors
       */
      private void processForm(final Node node, final List fors, final List ids,
              final List errors) {
          
          // Criteria 11.1
          if (node.getClass() == HTMLLabelElementImpl.class) {
              final Node forAttr = node.getAttributes().getNamedItem("for");
              if (forAttr == null) {
                  final ValidationError ve = new ValidationError(this,
                          "Missing 'for' attribute for 'label' element");
                  errors.add(ve);
                  
              } else {
                  final String value = forAttr.getNodeValue();
                  if (! fors.contains(value)) {
                      fors.add(value);
                  }
              }
              
          } else if (node.getClass() == HTMLInputElementImpl.class) {
              if ( 
"text".equals(node.getAttributes().getNamedItem("type").getNodeValue()) ) {
                  final Node idAttr = node.getAttributes().getNamedItem("id");
                  if (idAttr == null) {
                      final ValidationError ve = new ValidationError(this,
                              "Missing 'id' attribute for 'input' element");
                      errors.add(ve);
                      
                  } else {
                      final String value = idAttr.getNodeValue();
                      if (! ids.contains(value)) {
                          ids.add(value);
                      }
                  }
              }
          }
          
          Node child = node.getFirstChild();
          while (child != null) {
              processForm(child, fors, ids, errors);
              child = child.getNextSibling();
          }
      }
      
      /**
       * Validates a Frame Element.
       *
       * @param node The HTMLFrameElement.
       * @return ValidationError or null if no error occured.
       */
      protected ValidationError validateFrame( final HTMLFrameElement node ) {
          logger.info("validateFrame");
          
          // Criteria 2.1
          final Node name = node.getAttributes().getNamedItem("name");
          if (name == null) {
              final ValidationError ve = new ValidationError(this,
                      "Missing 'name' attribute for 'frame' element");
              return ve;
          }
          
          // Criteria 2.1 (Remarque)
          final String nameValue = 
JahiaTools.text2XMLEntityRef(name.getNodeValue(), 1);
          if (nameValue.indexOf(' ') > -1) {
              final ValidationError ve = new ValidationError(this,
                      "Attribute 'name' cannot contain any white space");
              return ve;
          }
          
          // Criteria 2.5
          final Node title = node.getAttributes().getNamedItem("title");
          if (title == null) {
              final ValidationError ve = new ValidationError(this,
                      "Missing 'title' attribute for 'frame' element");
              return ve;
          }
          
          // Criteria 2.10
          final Node scrolling = node.getAttributes().getNamedItem("scrolling");
          if (scrolling != null &&
                  "no".equals(scrolling.getNodeValue().toLowerCase())) {
              final ValidationError ve = new ValidationError(this,
                      "Scrolling should be set to at least 'auto' for frame " +
                      nameValue);
              return ve;
          }
          
          return null;
      }
      
      /**
       * Prints the content (at Log4j INFO level) of a Node and all its siblings
       * and children if the recursive parameter is set to TRUE.
       *
       * @param node The starting root node
       * @param indent The indent to put to distinguish bewteen levels
       * @param recursive If False, prints only the current Node
       *
       * @param throws DOMException If something goes wrong with node values
       */
      public static void print( final Node node, final String indent,
              final boolean recursive) throws DOMException {
          final StringBuffer buff = new StringBuffer();
          buff.append(indent).
                  append(node.getClass().getName()).
                  append(": NodeName '").append(node.getNodeName() 
).append("'").
                  append(", Attributes ");
          
          if (node.getAttributes() != null &&
                  node.getAttributes().getLength() > 0) {
              
              buff.append("{");
              for (int i=0; i<node.getAttributes().getLength(); i++) {
                  final Node n = node.getAttributes().item(i);
                  buff.append(n.getNodeName()).append("=").
                          append(n.getNodeValue()).append(",");
              }
              buff.deleteCharAt(buff.length() - 1);
              buff.append("}");
              
          } else {
              buff.append("{}");
          }
          
          buff.append(", NodeValue '").append(node.getNodeValue() ).append("'");
          
          logger.info(buff.toString());
          
          if (! recursive) { return; }
          
          Node child = node.getFirstChild();
          while (child != null) {
              print(child, indent + "\t", true);
              child = child.getNextSibling();
          }
      }
      
      public String toString() {
          return getClass().getName();
      }
  }
  
  
  
  Index: WAIValidatorTest.java
  ====================================================================
  /*
   *                                   ____.
   *                       __/\ ______|    |__/\.     _______
   *            __   .____|    |       \   |    +----+       \
   *    _______|  /--|    |    |    -   \  _    |    :    -   \_________
   *   \\______: :---|    :    :           |    :    |         \________>
   *           |__\---\_____________:______:    :____|____:_____\
   *                                      /_____|
   *
   *              . . . i n   j a h i a   w e   t r u s t . . .
   *
   *
   *
   * ----- BEGIN LICENSE BLOCK -----
   * Version: JCSL 1.0
   *
   * The contents of this file are subject to the Jahia Community Source License
   * 1.0 or later (the "License"); you may not use this file except in
   * compliance with the License. You may obtain a copy of the License at
   * http://www.jahia.org/license
   *
   * Software distributed under the License is distributed on an "AS IS" basis,
   * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
   * for the rights, obligations and limitations governing use of the contents
   * of the file. The Original and Upgraded Code is the Jahia CMS and Portal
   * Server. The developer of the Original and Upgraded Code is JAHIA Ltd. JAHIA
   * Ltd. owns the copyrights in the portions it created. All Rights Reserved.
   *
   * The Shared Modifications are Jahia View Helper.
   *
   * The Developer of the Shared Modifications is Jahia Solution Sàrl.
   * Portions created by the Initial Developer are Copyright (C) 2002 by the
   * Initial Developer. All Rights Reserved.
   *
   * ----- END LICENSE BLOCK -----
   */
  
  package org.jahia.services.htmlparser;
  
  import junit.framework.*;
  import junitx.framework.OrderedTestSuite;
  import org.jahia.engines.validation.EngineValidationHelper;
  import org.jahia.engines.validation.ValidationError;
  import org.cyberneko.html.parsers.DOMFragmentParser;
  import org.w3c.dom.Node;
  import org.w3c.dom.Document;
  import org.w3c.dom.DocumentFragment;
  import org.w3c.dom.html.HTMLDocument;
  import org.w3c.dom.html.HTMLBodyElement;
  import org.w3c.dom.html.HTMLAnchorElement;
  import org.w3c.dom.html.HTMLFormElement;
  import org.w3c.dom.html.HTMLTableElement;
  import org.apache.html.dom.HTMLDocumentImpl;
  
  import java.io.*;
  
  /**
   *
   * @author Xavier Lawrence
   */
  public class WAIValidatorTest extends TestCase {
      
      private static final org.apache.log4j.Logger logger =
              org.apache.log4j.Logger.getLogger(WAIValidatorTest.class);
      
      protected final String table =
              "<table width=\"200\" border=\"1\" summary=\"yop\">" +
                  "<tr>" +
                      "<th scope=\"col\">yop</th>" +
                      "<th scope=\"col\">&nbsp;</th>" +
                      "<th scope=\"col\">&nbsp;</th>" +
                  "</tr>" +
                  "<tr>" +
                      "<td headers=\"good\">a</td>" +
                      "<td headers=\"good\">&nbsp;</td>" +
                      "<td headers=\"good\">&nbsp;</td>" +
                  "</tr>" +
                  "<tr>" +
                      "<td headers=\"good\">&nbsp;</td>" +
                      "<td headers=\"good\">&nbsp;</td>" +
                      "<td headers=\"good\">&nbsp;</td>" +
                  "</tr>" +
                  "<caption>Enorme</caption>" +
              "</table>";
      
      protected final String table2 =
              "<TABLE border=\"1\"" + 
                  "summary=\"This table charts the number of cups" +
                  "of coffee consumed by each senator, the type" + 
                  "of coffee (decaf or regular), and whether" + 
                  "taken with sugar.\">" +
                  "<CAPTION>Cups of coffee consumed by each senator</CAPTION>" +
                  "<TR>" +
                      "<TH id=\"t1\">Name</TH>" +
                      "<TH id=\"t2\">Cups</TH>" +
                      "<TH id=\"t3\" abbr=\"Type\">Type of Coffee</TH>" +
                      "<TH id=\"t4\">Sugar?</TH>" +
                  "<TR>" +
                      "<TD headers=\"t12\">T. Sexton</TD>" +
                      "<TD headers=\"t2\">10</TD>" +
                      "<TD headers=\"t3\">Espresso</TD>" +
                      "<TD headers=\"t4\">No</TD>" +
                  "<TR>" +
                      "<TD headers=\"t1\">J. Dinnen</TD>" +
                      "<TD headers=\"t2\">5</TD>" +
                      "<TD headers=\"t3\">Decaf</TD>" +
                      "<TD headers=\"t4\">Yes</TD>" +
              "</TABLE>" ;
      
      protected final String links = 
              "<p> Le 1er super lien   " +
                  "<a title=' prout' 
href=\"/jahia/Jahia/lang/en/pid/3\">888888888888888888888888888888888888888888888888888888888888888888888888888848</a>"
 +
              "</p>" +
              "<p> Le 2ème super lien   " +
                  "<a title=' prout' class='link' 
href=\"/jahia/Jahia/lang/en/pid/2\" >c'est super  </a>" +
              "</p>";
      
      protected final String form = 
              "<FORM action=\"...\" method=\"post\">" +
                  "<TABLE>" +
                      "<TR>" +
                          "<TD><LABEL for=\"fname\">First Name</LABEL>" +
                          "<TD><INPUT type=\"text\" name=\"firstname\" 
id=\"fname\">" +
                      "</TR>" +
                      "<TR>" +
                          "<TD><LABEL for=\"lname\">Last Name</LABEL>" +
                          "<TD><INPUT type=\"text\" name=\"lastname\" 
id=\"lname\">" +
                      "</TR>" +
                  "</TABLE>" +
                  "<INPUT type=\"submit\" value=\"Send\"> <INPUT 
type=\"reset\">" +
              "</FORM>";
  
      public WAIValidatorTest(String testName) {
          super(testName);
      }
  
      public static Test suite() {
          return new OrderedTestSuite(WAIValidatorTest.class);
      }
  
      /**
       * Test of validate method, of class 
org.jahia.services.htmlparser.WAIValidator.
       */
      public void testzValidate() throws Exception {
          logger.info("*** testValidate ***");
          final StringBuffer buff = new StringBuffer();
          buff.append("<html>");
          buff.append(form);
          buff.append(table);
          buff.append(table2);
          buff.append(links);
          buff.append("</html> ");
          final WAIValidator waiValidator = new WAIValidator();
          final EngineValidationHelper evh = 
waiValidator.validate(buff.toString());
          logger.info("evh: "+ evh);
          
          assertTrue(evh == null || !evh.hasErrors());
      }
  
      /**
       * Test of print method, of class 
org.jahia.services.htmlparser.WAIValidator.
       */
      public void testPrint() throws Exception {
          logger.info("*** testPrint ***");
          final File tempFile = File.createTempFile("tmp", ".html");
          
          final StringBuffer buff = new StringBuffer();
          buff.append("<html>");
          buff.append(form);
          buff.append(table);
          buff.append(table2);
          buff.append(links);
          buff.append("</html> ");
          
          try {
              final FileOutputStream fos = new FileOutputStream(tempFile);
              fos.write(buff.toString().getBytes());
              fos.flush();
              fos.close();
              
              final DOMFragmentParser parser = new DOMFragmentParser();
              final EngineValidationHelper evh = new EngineValidationHelper();
              final HTMLDocument document = new HTMLDocumentImpl();
              final DocumentFragment fragment = 
document.createDocumentFragment();
              parser.parse(tempFile.getAbsolutePath(), fragment);
              WAIValidator.print(fragment, " ", true);
              
              assertTrue(fragment != null);
              
          } catch (Exception e) {
              throw e;
              
          } finally {
              tempFile.delete();
          }
      }
      
      /**
       * Test of validateTable method, of class 
org.jahia.services.htmlparser.WAIValidator.
       */
      public void testValidateTable() throws Exception { 
          logger.info("*** testValidateTable ***");
  
          final StringBuffer buff = new StringBuffer();
          buff.append("<html>");
          buff.append(table);
          buff.append(table2);
          buff.append("</html> ");
          
          final WAIValidator waiValidator = new WAIValidator();
          final EngineValidationHelper evh = 
waiValidator.validate(buff.toString());
          logger.info("evh: "+ evh);
          
          assertTrue(evh == null || !evh.hasErrors());
      }
      
      /**
       * Test of validateLink method, of class 
org.jahia.services.htmlparser.WAIValidator.
       */
      public void testValidateLink() throws Exception {
          logger.info("*** testValidateLink ***");
          
          final StringBuffer buff = new StringBuffer();
          buff.append("<html>");
          buff.append(links);
          buff.append("</html> ");
  
          final WAIValidator waiValidator = new WAIValidator();
          final EngineValidationHelper evh = 
waiValidator.validate(buff.toString());
          logger.info("evh: "+ evh);
          
          assertTrue(evh == null || !evh.hasErrors());
      }
      
      /**
       * Test of validateForm method, of class 
org.jahia.services.htmlparser.WAIValidator.
       */
      public void testValidateForm() throws Exception {
          logger.info("*** testValidateForm ***");
          
          final StringBuffer buff = new StringBuffer();
          buff.append("<html>");
          buff.append(form);
          buff.append("</html> ");
          
          final WAIValidator waiValidator = new WAIValidator();
          final EngineValidationHelper evh = 
waiValidator.validate(buff.toString());
          logger.info("evh: "+ evh);
          
          assertTrue(evh == null || !evh.hasErrors());
      }
  }
  

Reply via email to