You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@struts.apache.org by gv...@apache.org on 2006/07/03 23:53:03 UTC

svn commit: r418860 - in /struts/shale/trunk/shale-clay/src: main/java/org/apache/shale/clay/ main/java/org/apache/shale/clay/parser/ main/java/org/apache/shale/clay/parser/builder/chain/ main/java/org/apache/shale/clay/taglib/ main/resources/META-INF/...

Author: gvanmatre
Date: Mon Jul  3 14:53:02 2006
New Revision: 418860

URL: http://svn.apache.org/viewvc?rev=418860&view=rev
Log:
This commit contains a couple related fixes for SHALE-209 and SHALE-208 .  I found that the clay parser was not handling cdata sections when used by a custom tag validator.

Added:
    struts/shale/trunk/shale-clay/src/main/java/org/apache/shale/clay/taglib/ClayTagValidator.java   (with props)
Removed:
    struts/shale/trunk/shale-clay/src/main/java/org/apache/shale/clay/Bundle.properties
Modified:
    struts/shale/trunk/shale-clay/src/main/java/org/apache/shale/clay/parser/Node.java
    struts/shale/trunk/shale-clay/src/main/java/org/apache/shale/clay/parser/Parser.java
    struts/shale/trunk/shale-clay/src/main/java/org/apache/shale/clay/parser/builder/chain/DefaultBuilderRule.java
    struts/shale/trunk/shale-clay/src/main/java/org/apache/shale/clay/taglib/SymbolTag.java
    struts/shale/trunk/shale-clay/src/main/resources/META-INF/shale-clay.tld
    struts/shale/trunk/shale-clay/src/main/resources/org/apache/shale/clay/Bundle.properties
    struts/shale/trunk/shale-clay/src/test/java/org/apache/shale/clay/parser/ParserTestCase.java

Modified: struts/shale/trunk/shale-clay/src/main/java/org/apache/shale/clay/parser/Node.java
URL: http://svn.apache.org/viewvc/struts/shale/trunk/shale-clay/src/main/java/org/apache/shale/clay/parser/Node.java?rev=418860&r1=418859&r2=418860&view=diff
==============================================================================
--- struts/shale/trunk/shale-clay/src/main/java/org/apache/shale/clay/parser/Node.java (original)
+++ struts/shale/trunk/shale-clay/src/main/java/org/apache/shale/clay/parser/Node.java Mon Jul  3 14:53:02 2006
@@ -49,6 +49,12 @@
      */
     private boolean isEnd = false;
     
+    
+    /**
+     * <p>This flag indicates the node is a CDATA node.</p>
+     */
+    private boolean isCdata = false;
+    
     /**
      * <p>This boolean flag has a <code>true</code> value if the 
      * node has a starting and ending node.  Not all nodes will be
@@ -238,6 +244,7 @@
         buff.append("name=").append(name).append(" isStart=").append(isStart)
         .append(" isEnd=").append(isEnd).append(" isWellFormed=")
         .append(isWellFormed).append(" isComment=").append(isComment)
+        .append(" isCdata=").append(isCdata)
         .append("\n").append(token).append("\n").append(attributes);
         return buff.toString();
     }
@@ -260,8 +267,27 @@
     public void setComment(boolean isComment) {
         this.isComment = isComment;
     }
+
      
- 
+    /**
+     * <p> Returns <code>true</code> if the node is
+     * a CDATA; otherwise; the default is <code>false</code>.
+     * </p>.
+     */
+    public boolean isCdata() {
+        return isCdata;
+    }
+    
+
+    /**
+     * <p>Sets a boolean value that identifies this node as
+     * being a CDATA.  This could be a starting, ending or
+     * within the body.</p>
+     */
+    public void setCdata(boolean isCdata) {
+        this.isCdata = isCdata;
+    }
+
     /**
      * <p>Finds matching nodes by <code>name</code> searching thru all the children.</p>
      */

Modified: struts/shale/trunk/shale-clay/src/main/java/org/apache/shale/clay/parser/Parser.java
URL: http://svn.apache.org/viewvc/struts/shale/trunk/shale-clay/src/main/java/org/apache/shale/clay/parser/Parser.java?rev=418860&r1=418859&r2=418860&view=diff
==============================================================================
--- struts/shale/trunk/shale-clay/src/main/java/org/apache/shale/clay/parser/Parser.java (original)
+++ struts/shale/trunk/shale-clay/src/main/java/org/apache/shale/clay/parser/Parser.java Mon Jul  3 14:53:02 2006
@@ -258,7 +258,11 @@
             
             //play forward on comments making all nodes child nodes until a 
             //ending comment is hit
-            if (node.isComment() && node.isStart()) {
+            if ((node.isComment() || node.isCdata()) && node.isStart()) {
+                
+                // capture the type of block since you can have comments in a cdata block
+                boolean isCommentBlock = node.isComment();
+                boolean isCdataBlock = node.isCdata();
                 
                 //not self contained comment
                 if (!node.isEnd()) {
@@ -266,25 +270,29 @@
                     trash: while (i.hasNext()) {
                         token = (Token) i.next();
                         Node bodyNode = buildNode(token);
-                        if (bodyNode.isComment() && bodyNode.isEnd()) { 
+                        //if a ending node and the block matches
+                        if (((bodyNode.isComment() && isCommentBlock) 
+                             || (bodyNode.isCdata() && isCdataBlock)) && bodyNode.isEnd()) { 
                             node.addChild(bodyNode);  
                             node.setEnd(true);
                             node.setWellFormed(true);
                             break trash;
                         } else {
-                            //force all nodes to be comment within a comment
-                            node.setComment(true);
+                            //force all nodes to be comment or cdata within a block
+                            node.setComment(isCommentBlock);
+                            node.setCdata(isCdataBlock);
                             node.setWellFormed(true);
                             node.addChild(bodyNode);
                         }                        
                     } // end while
                 
-                } 
+                }
                 
                 current.addChild(node);
                 continue next;
                 
-            } // end is comment
+            } 
+            
             
             if (!node.isStart() && node.isEnd()) {
                           
@@ -357,7 +365,7 @@
                     new Object[] {node.getToken(), node.getToken().getRawText()}));              
         }
           
-        if (!node.isComment()) {
+        if (!node.isComment() && !node.isCdata()) {
             Iterator ci = node.getChildren().iterator();
             while (ci.hasNext()) {
                 simpleWellFormedCheck((Node)(ci.next()));
@@ -465,6 +473,44 @@
         new Rule('>', false, -1, true),
         new Rule('-', false, -2, true),
         new Rule('-', false, -3, true)};
+
+    
+    /**
+     * <p>Declare an array of {@link Parser.Rule}s that validate self contained CDATA {@link Token}.</p>
+     */    
+    private static Rule[] SELF_CONTAINED_CDATA_RULES = {new Rule('<', true, 0, true),
+        new Rule('!', true, 1, true),
+        new Rule('[', true, 2, true),        
+        new Rule('C', true, 3, true),        
+        new Rule('D', true, 4, true),        
+        new Rule('A', true, 5, true),        
+        new Rule('T', true, 6, true),        
+        new Rule('A', true, 7, true),        
+        new Rule('[', true, 8, true),        
+        new Rule('>', false, -1, true),
+        new Rule(']', false, -2, true),
+        new Rule(']', false, -3, true)};
+    
+    /**
+     * <p>Declare an array of {@link Parser.Rule}s that validate a begin CDATA {@link Token}.</p>
+     */    
+    public static Rule[] BEGIN_CDATA_RULES = {new Rule('<', true, 0, true),
+        new Rule('!', true, 1, true),
+        new Rule('[', true, 2, true),
+        new Rule('C', true, 3, true),        
+        new Rule('D', true, 4, true),        
+        new Rule('A', true, 5, true),        
+        new Rule('T', true, 6, true),        
+        new Rule('A', true, 7, true),        
+        new Rule('[', true, 8, true)};
+    
+    /**
+     * <p>Declare an array of {@link Parser.Rule}s that validate an end CDATA {@link Token}.</p>
+     */    
+    public static Rule[] END_CDATA_RULES = {new Rule('>', false, -1, true),
+        new Rule(']', false, -2, true),
+        new Rule(']', false, -3, true)};
+
     
     /**
      * <p>Declare an array of {@link Parser.Rule}s that validate a begin comment {@link Token}.</p>
@@ -513,14 +559,17 @@
      *  that are used to determine the type of {@link Node} the {@link Token} defines.</p>
      */
     private static Shape[] NODE_SHAPES = {
-        new Shape(false, true, false, END_TAG_RULES),
-        new Shape(true, true, false, SELF_TERM_TAG_RULES),
-        new Shape(true, true, true, SELF_CONTAINED_COMMENT_RULES),
-        new Shape(true, false, true, BEGIN_COMMENT_TAG_RULES),
-        new Shape(false, true, true, END_COMMENT_TAG_RULES),
-        new Shape(true, true, true, DOCTYPE_TAG_RULES),
-        new Shape(true, false, false, BEGIN_TAG_RULES),
-        new Shape(true, true, true, JSP_RULES)};
+        new Shape(true, true, false, true, SELF_CONTAINED_CDATA_RULES),
+        new Shape(true, false, false, true, BEGIN_CDATA_RULES),
+        new Shape(false, true, false, true, END_CDATA_RULES),   
+        new Shape(false, true, false, false, END_TAG_RULES),
+        new Shape(true, true, false, false, SELF_TERM_TAG_RULES),
+        new Shape(true, true, true, false, SELF_CONTAINED_COMMENT_RULES),
+        new Shape(true, false, true, false, BEGIN_COMMENT_TAG_RULES),
+        new Shape(false, true, true, false, END_COMMENT_TAG_RULES),
+        new Shape(true, true, true, false, DOCTYPE_TAG_RULES),
+        new Shape(true, false, false, false, BEGIN_TAG_RULES),
+        new Shape(true, true, true, false, JSP_RULES)};
     
     
     /**
@@ -572,6 +621,7 @@
             node.setStart(shape.isStart());
             node.setEnd(shape.isEnd());
             node.setComment(shape.isComment());
+            node.setCdata(shape.isCdata);
             
             break nextShape;
         }
@@ -592,6 +642,10 @@
                 
                 node.setName("--");
                 
+            } else if (node.isCdata()) {
+                
+                node.setName("[CDATA[");    
+                
             } else {
                 // find the node name delimiter
                 //int e = token.getDocument().indexOf(" ", token.getBeginOffset() + 2);
@@ -640,7 +694,7 @@
         node.setAttributes(attributes);
         
         // look for attribute in a beginning tag only
-        if (node.isStart() && !node.isComment()) {
+        if (node.isStart() && (!node.isComment() && !node.isCdata())) {
             
             int e = (node.isStart() && node.isEnd()) ? (token.getEndOffset() - 2)
                     : (token.getEndOffset() - 1);
@@ -780,6 +834,13 @@
          * <p>If <code>true</code> it indicates a comment node.</p>
          */
         private boolean isComment = false;
+
+
+        /**
+         * <p>If <code>true</code> it indicates a CDATA node.</p>
+         */
+        private boolean isCdata = false;
+
         
         /**
          * <p>An array of {@link Parser.Rule}s used to determine if the
@@ -790,10 +851,11 @@
         /**
          * <p>Overloaded constructor used to instantiate the immutable object.</p> 
          */
-        public Shape(boolean isStart, boolean isEnd, boolean isComment, Rule[] rules) {
+        public Shape(boolean isStart, boolean isEnd, boolean isComment, boolean isCdata, Rule[] rules) {
             this.isStart = isStart;
             this.isEnd = isEnd;
             this.isComment = isComment;
+            this.isCdata = isCdata;
             this.rules = rules;
         }
         
@@ -815,6 +877,13 @@
         public boolean isComment() {
             return isComment;    
         }
+        /**
+         * <p>Returns <code>true</code> if the {@link Token} is a CDATA tag.</p>
+         */
+        public boolean isCdata() {
+            return isCdata;    
+        }
+               
         /**
          * <p>Returns the {@link Parser.Rule}s that define the <code>isStart</code>, 
          * <code>isEnd</code> and <code>isComment</code> characteristics.</p>

Modified: struts/shale/trunk/shale-clay/src/main/java/org/apache/shale/clay/parser/builder/chain/DefaultBuilderRule.java
URL: http://svn.apache.org/viewvc/struts/shale/trunk/shale-clay/src/main/java/org/apache/shale/clay/parser/builder/chain/DefaultBuilderRule.java?rev=418860&r1=418859&r2=418860&view=diff
==============================================================================
--- struts/shale/trunk/shale-clay/src/main/java/org/apache/shale/clay/parser/builder/chain/DefaultBuilderRule.java (original)
+++ struts/shale/trunk/shale-clay/src/main/java/org/apache/shale/clay/parser/builder/chain/DefaultBuilderRule.java Mon Jul  3 14:53:02 2006
@@ -63,7 +63,7 @@
 
         BuilderRuleContext builderRuleContext = (BuilderRuleContext) context;
         Node node = builderRuleContext.getNode();
-        if (node.isComment()) {
+        if (node.isComment() || node.isCdata()) {
             builderRuleContext.setBuilder(builders[0]);   
         } else  if (node.getName() != null && node.getAttributes().containsKey("jsfid")) {
             builderRuleContext.setBuilder(builders[1]);     

Added: struts/shale/trunk/shale-clay/src/main/java/org/apache/shale/clay/taglib/ClayTagValidator.java
URL: http://svn.apache.org/viewvc/struts/shale/trunk/shale-clay/src/main/java/org/apache/shale/clay/taglib/ClayTagValidator.java?rev=418860&view=auto
==============================================================================
--- struts/shale/trunk/shale-clay/src/main/java/org/apache/shale/clay/taglib/ClayTagValidator.java (added)
+++ struts/shale/trunk/shale-clay/src/main/java/org/apache/shale/clay/taglib/ClayTagValidator.java Mon Jul  3 14:53:02 2006
@@ -0,0 +1,164 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * 
+ * $Id$
+ */
+
+package org.apache.shale.clay.taglib;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.servlet.jsp.tagext.PageData;
+import javax.servlet.jsp.tagext.TagLibraryValidator;
+import javax.servlet.jsp.tagext.ValidationMessage;
+
+import org.apache.shale.clay.parser.Node;
+import org.apache.shale.clay.parser.Parser;
+import org.apache.shale.util.Messages;
+
+/**
+ * <p>Validates the JSP page for the clay namespace, 
+ * "http://struts.apache.org/shale/clay-plugin".  This tag
+ * validator checks to make sure that there are not any nested 
+ * tags under the {@link ClayTag} with the exception of the 
+ * {@link SymbolTag}.</p> 
+ */
+public class ClayTagValidator extends TagLibraryValidator {
+
+    private static final String CLAY_URI_NAMESPACE = "http://struts.apache.org/shale/clay-plugin";
+    
+    /**
+     * <p>Message resources for this class.</p>
+     */
+    private static Messages messages = new Messages("org.apache.shale.clay.Bundle",
+            ClayTagValidator.class.getClassLoader());
+   
+    /**
+     * <p>Loads the <code>page</code> content into a <code>StringBuffer</code>.</p>
+     */
+    protected StringBuffer loadTemplate(PageData page) throws IOException {
+        
+        
+        StringBuffer buff = new StringBuffer();
+        InputStream inputStream = page.getInputStream();
+        
+            int c = 0;
+            done: while (true) {
+                c = inputStream.read();
+                if (c > -1)
+                    buff.append((char) c);
+                else
+                    break done;
+                
+            }
+
+            return buff;
+        
+    }
+
+    /**
+     * <p>Creates a <code>ValidationMessage</code> for a {@link ClayTag} containing 
+     * a child of anything other than the {@link SymbolTag}.</p>
+     */
+    private ValidationMessage getMessage(String prefix, Node clayNode, Node childNode) {
+       Object[] args = {clayNode.getToken().getRawText(),
+                        childNode.getToken().getRawText(),
+                        prefix};
+       String jspid = (String) childNode.getAttributes().get("jsp:id");
+       String message = messages.getMessage("invalid.nested.tag", args);
+       return new ValidationMessage(jspid, message);
+    }
+    
+   
+    /**
+     * <p>Checks the child nodes of the <code>clayNode</code> verifying that
+     * only the symbol node is present.</p>
+     */
+    private void checkForInvalidNestedTags(String prefix, Node clayNode, List messages) {
+        List children = clayNode.getChildren();
+        next: for (int i = 0; i < children.size(); i++) {
+            Node child = (Node) children.get(i);
+            if ((!child.isComment() && !child.isCdata()) && child.isWellFormed()) { 
+                if (child.getQname() != null && child.getName() != null) {
+                    
+                    if (child.getQname().equals("jsp") && child.getName().equals("text")) {         
+                        continue next;
+                    }  else if (!child.getName().equals("symbol") || !prefix.equals(child.getQname())) {
+                        messages.add(getMessage(prefix, clayNode, child));           
+                    }
+                }
+                
+            }
+        }
+    }
+    
+    /**
+     * <p>Recursively walks the parsed document looking for clay component nodes.  The children  
+     * are checked to make sure the symbol tag is the only valid child tag.</p>
+     */
+    private void validateClayTags(String prefix, Node node, List messages) {
+       if ((!node.isComment() && !node.isCdata()) && node.isWellFormed() 
+           && node.getName() != null && node.getName().equals("clay") 
+           && node.getQname() != null && node.getQname().equals(prefix)) {
+           
+           checkForInvalidNestedTags(prefix, node, messages);
+           return;
+       }
+       
+       List children = node.getChildren();
+       for (int i = 0; i < children.size(); i++) {
+          Node child = (Node) children.get(i);
+          validateClayTags(prefix, child, messages);
+       }
+        
+    }
+    
+    /**
+     * <p>Validates the page for a directive with a uri of 
+     * "<strong>http://struts.apache.org/shale/clay-plugin</strong>".
+     */    
+    public ValidationMessage[] validate(String prefix, String uri, PageData page) {
+        List messages = new ArrayList();
+        
+        if (uri != null && CLAY_URI_NAMESPACE.equals(uri)) {
+            try {
+                StringBuffer buff = loadTemplate(page);
+                Parser p = new Parser();
+                List roots = p.parse(buff);
+                
+                for (int i = 0;  i < roots.size(); i++) {
+                    Node node = (Node) roots.get(i);  
+                    validateClayTags(prefix, node, messages);                    
+                }
+                
+            } catch (IOException e) {
+                messages.add(new ValidationMessage(null, e.getMessage()));
+            }
+        }
+        
+        if (messages.isEmpty())
+            return null;
+        else {
+            ValidationMessage[] validationMessages = new ValidationMessage[messages.size()];
+            messages.toArray(validationMessages);
+            return validationMessages;
+        }
+        
+    }
+
+}

Propchange: struts/shale/trunk/shale-clay/src/main/java/org/apache/shale/clay/taglib/ClayTagValidator.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: struts/shale/trunk/shale-clay/src/main/java/org/apache/shale/clay/taglib/ClayTagValidator.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Modified: struts/shale/trunk/shale-clay/src/main/java/org/apache/shale/clay/taglib/SymbolTag.java
URL: http://svn.apache.org/viewvc/struts/shale/trunk/shale-clay/src/main/java/org/apache/shale/clay/taglib/SymbolTag.java?rev=418860&r1=418859&r2=418860&view=diff
==============================================================================
--- struts/shale/trunk/shale-clay/src/main/java/org/apache/shale/clay/taglib/SymbolTag.java (original)
+++ struts/shale/trunk/shale-clay/src/main/java/org/apache/shale/clay/taglib/SymbolTag.java Mon Jul  3 14:53:02 2006
@@ -12,6 +12,8 @@
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
+ * 
+ * $Id$
  */
 package org.apache.shale.clay.taglib;
 

Modified: struts/shale/trunk/shale-clay/src/main/resources/META-INF/shale-clay.tld
URL: http://svn.apache.org/viewvc/struts/shale/trunk/shale-clay/src/main/resources/META-INF/shale-clay.tld?rev=418860&r1=418859&r2=418860&view=diff
==============================================================================
--- struts/shale/trunk/shale-clay/src/main/resources/META-INF/shale-clay.tld (original)
+++ struts/shale/trunk/shale-clay/src/main/resources/META-INF/shale-clay.tld Mon Jul  3 14:53:02 2006
@@ -27,6 +27,12 @@
   <uri>http://struts.apache.org/shale/clay-plugin</uri>
   <description></description>
 
+  <validator>
+  	<validator-class>
+  		org.apache.shale.clay.taglib.ClayTagValidator
+  	</validator-class>
+  </validator>
+
   <listener>
     <listener-class>org.apache.shale.clay.config.ClayConfigureListener</listener-class>
   </listener>

Modified: struts/shale/trunk/shale-clay/src/main/resources/org/apache/shale/clay/Bundle.properties
URL: http://svn.apache.org/viewvc/struts/shale/trunk/shale-clay/src/main/resources/org/apache/shale/clay/Bundle.properties?rev=418860&r1=418859&r2=418860&view=diff
==============================================================================
--- struts/shale/trunk/shale-clay/src/main/resources/org/apache/shale/clay/Bundle.properties (original)
+++ struts/shale/trunk/shale-clay/src/main/resources/org/apache/shale/clay/Bundle.properties Mon Jul  3 14:53:02 2006
@@ -40,6 +40,9 @@
 attributes.total.found=Found {0} attribute(s).
 attribute.token.range=Attribute token offset range({0} - {1}).
 
+#org.apache.shale.clay.taglib.ClayTagValidator
+invalid.nested.tag=Tag "{0}" contains an invalid nested tag "{1}"\n Only the "{2}:symbol" tag is the only valid nested tag under the clay component.
+
 #org.apache.shale.clay.component.Clay
 clay.jsfid.notfound=Component not found "{0}".
 clay.jsfid.null=The Component jsfid attribute is null.  The cause is most likely a\nmissing "clayJsfid" attribute when using HTML templates and nesting \na clay component.  It is also likely that the problem was caused by using \ngeneric templates with symbol replacement of the clayJsfid={0}.

Modified: struts/shale/trunk/shale-clay/src/test/java/org/apache/shale/clay/parser/ParserTestCase.java
URL: http://svn.apache.org/viewvc/struts/shale/trunk/shale-clay/src/test/java/org/apache/shale/clay/parser/ParserTestCase.java?rev=418860&r1=418859&r2=418860&view=diff
==============================================================================
--- struts/shale/trunk/shale-clay/src/test/java/org/apache/shale/clay/parser/ParserTestCase.java (original)
+++ struts/shale/trunk/shale-clay/src/test/java/org/apache/shale/clay/parser/ParserTestCase.java Mon Jul  3 14:53:02 2006
@@ -749,7 +749,33 @@
         // default namespace
         uri = clayComponent.getNamespaceURI(null);
         assertEquals("uri", "http://www.w3.org/1999/xhtml", uri);
-
+        
+    }
+    
+    
+    public void testParseCDATA() {
+        Parser p = new Parser();
+        StringBuffer doc = new StringBuffer();
+        doc.append("<jsp:text\njsp:id=\"9\"\n><![CDATA[\n<html>\n]]>\n</jsp:text>");
+        doc.append("<jsp:text\njsp:id=\"10\"\n><![CDATA[\n<head>\n]]>\n</jsp:text>");
+        doc.append("<jsp:text\njsp:id=\"11\"\n><![CDATA[\n</title>\n]]>\n</jsp:text>");
+        doc.append("<jsp:text\njsp:id=\"12\"\n><![CDATA[\n<!-- </title> -->\n]]>\n</jsp:text>");
+        
+        List roots = p.parse(doc);
+        assertEquals(4, roots.size());
+        
+        for (int i = 0; i < roots.size(); i++) {
+           Node node = (Node) roots.get(i);  
+           assertEquals("jsp", node.getQname());
+           assertEquals("text", node.getName());
+           
+           String id = (String) node.getAttributes().get("jsp:id");
+           assertEquals(String.valueOf(i + 9), id);
+           
+           
+           
+        }
+   
         
     }