推荐文章,从ibm相关网站得到!~
 
技巧:使用 DOM NodeFilter 
控制哪些节点对于 TreeWalker 或 NodeIterator 是可见的Nicholas Chase([email protected]
总裁,Chase and Chase Inc.
2002 年 11 月XML 的 DOM 级别 2 Traversal 模块提供了两个新对象,TreeWalker 和 NodeIterator,这简化了导航 Document 的过程。另外,该模块定义了 NodeFilter - 它能用于通过编程来控制什么节点对于 TreeWalker 或 NodeFilter 是可见的。本技巧文章向您演示了如何创建 NodeFilter 以及使用它的 Traversal 对象。
注:本技巧文章使用 JAXP,但是样本应用程序也可与 Xerces-Java 2 一起使用,这个概念可应用于任何 XML 解析器环境。 源代码
本技巧文章创建了遍历简单 XML 文档的应用程序,该文档包含了有关紧急情况下联系哪些雇员的信息:清单 1. 源文档
<?xml version="1.0"?>
<personnel>
   <employee empid="332" status="contact">
        <deptid>24</deptid>
        <shift>night</shift>
        <name>Jenny Berman</name>
   </employee>
   <!-- Other employees listed here -->
</personnel>
 最后,该应用程序依靠 NodeFilter 来消除 status 值为 donotcontact 的雇员。遍历树
文档对象模型(DOM)级别 2 Traversal 模块定义了遍历 XML 文档树的对象,显示有关当前 Node 的信息。创建 TreeWalker 的全过程在技巧文章 Traversing an XML document with a TreeWalker 中已作了描述,但为了方便起见,请考虑这个应用程序,该应用程序显示了雇员文档的元素:清单 2. 创建 TreeWalker
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.File;
import org.w3c.dom.Document;
import org.w3c.dom.DOMImplementation;
import org.w3c.dom.Node;
import org.w3c.dom.traversal.DocumentTraversal;
import org.w3c.dom.traversal.TreeWalker;
import org.w3c.dom.traversal.NodeIterator;
import org.w3c.dom.traversal.NodeFilter;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Element;public class ShowDocument {    public static void main (String args[]) {
       File docFile = new File("employees.xml");
                
       Document doc = null;
       try {
          DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
          DocumentBuilder db = dbf.newDocumentBuilder();
        
          doc = db.parse(docFile);
       } catch (Exception e) {
           System.out.print("Problem parsing the file.");
       }       DOMImplementation domimpl = doc.getImplementation();
       if (domimpl.hasFeature("Traversal", "2.0")) {           Node root = doc.getDocumentElement();
           int whattoshow = NodeFilter.SHOW_ALL;
          NodeFilter nodefilter = null; 
           boolean expandreferences = false;           DocumentTraversal traversal = (DocumentTraversal)doc;
  
           TreeWalker walker = traversal.createTreeWalker(root, 
                                                          whattoshow, 
                                                          nodefilter, 
                                                          expandreferences);
           Node thisNode = null;
           thisNode = walker.nextNode();
           while (thisNode != null) {
              if (thisNode.getNodeType() == thisNode.ELEMENT_NODE) {
                 System.out.print(thisNode.getNodeName() + " ");
                 Element thisElement = (Element)thisNode;
                 NamedNodeMap attributes = thisElement.getAttributes();
                 System.out.print("(");
                 for (int i = 0; i < attributes.getLength(); i++) {
                    System.out.print(attributes.item(i).getNodeName() + "=\"" +
                                     attributes.item(i).getNodeValue() + "\" ");
                 }
                 System.out.print(") : ");
              } else if (thisNode.getNodeType() == thisNode.TEXT_NODE) {
                 System.out.print(thisNode.getNodeValue());
              }
              thisNode = walker.nextNode();
          }        } else {
           System.out.println("The Traversal module isn't supported.");
        }
   }
}
 当 TreeWalker 遍历 Document 树时,它显示 Element 名称、属性和 Text Node:清单 3. 应用程序输出 - 所有节点
personnel () :
   employee (empid="332" status="contact" ) :
        deptid () : 24
        shift () : night
        name () : Jenny Berman   employee (empid="994" status="donotcontact" ) :
        deptid () : 24
        shift () : day
        name () : Andrew Fule   employee (empid="948" status="contact" ) :
        deptid () : 3
        shift () : night
        name () : Anna Bangle
 请注意在 TreeWalker 创建期间传递的参数之一是 NodeFilter 对象,该参数已被设置成 null。其结果是,TreeWalker 看见了 Document 中所有满足 whattoshow 值为 NodeFilter.SHOW_ALL 的 Node。创建 NodeFilter
创建 NodeFilter 对象使您可以对 TreeWalker 对象所看到的 Node 进行细粒度的控制。只需要一个实现 NodeFilter 接口的类就可以了,该类由单个方法 acceptNode() 所组成。当 TreeWalker 遇到 Node,将其传递给 acceptNode() 方法以决定是否可以接收该 Node。因为这是定制的类,所以您可以基于能装入应用程序的任何内容作出判断。在本文的例子中,判断基于 status 属性的值:清单 4. 实现 NodeFilter
import org.w3c.dom.traversal.NodeFilter;
import org.w3c.dom.Node;
import org.w3c.dom.Element;public class EmployeeFilter implements NodeFilter {     public short acceptNode(Node thisNode) { 
         if (thisNode.getNodeType() == Node.ELEMENT_NODE) { 
              Element e = (Element)thisNode; 
              if (e.getAttribute("status").equals("donotcontact")) {
                   return NodeFilter.FILTER_SKIP; 
              }  
         } 
         return NodeFilter.FILTER_ACCEPT; 
    } 

 检查每个 Node 以确定它是否是 Element。如果是,则检查 status 属性(若有的话)。过滤器跳过所有 status 属性为 donotcontact 的元素,而接受其它所有元素。现在所要做的就是创建带有新的 NodeFilter 对象的 TreeWalker:清单 5. 设置 TreeWalker 以查看 NodeFilter
...
           Node root = doc.getDocumentElement();
           int whattoshow = NodeFilter.SHOW_ALL;
           NodeFilter nodefilter = new EmployeeFilter(); 
           boolean expandreferences = false;           DocumentTraversal traversal = (DocumentTraversal)doc;
  
           TreeWalker walker = traversal.createTreeWalker(root, 
                                                          whattoshow, 
                                                          nodefilter, 
                                                          expandreferences);
...
 现在,当 TreeWalker 遍历 Document 时,它根据 EmployeeFilter 对象检查每个 Node,因此它跳过包含 status 属性为 donotcontact 的 Node:清单 6. 结果
personnel () :
   employee (empid="332" status="contact" ) :
        deptid () : 24
        shift () : night
        name () : Jenny Berman
        deptid () : 24
        shift () : day
        name () : Andrew Fule   employee (empid="948" status="contact" ) :
        deptid () : 3
        shift () : night
        name () : Anna Bangle 请注意 employee 元素不见了,但其子元素还在。有些情况下,比如本应用程序,这并不是您真正想要的。您不想跳过 Node,而是想彻底拒绝它。FILTER_SKIP vs. FILTER_REJECT
当 TreeWalker 跳过一个 Node 后,它移到下一个遇到的 Node。有些情况下,这是原始元素的子元素。对于本应用程序来说,您正尝试消除不该联系的雇员,因此不只是要跳过雇员元素,而是要拒绝这个元素及其所有子元素。通过将 NodeFilter 更改成使用 FILTER_REJECT 而不是使用 FILTER_SKIP,您就能很容易做到这一点:清单 7. 拒绝 Node
...
         if (thisNode.getNodeType()==Node.ELEMENT_NODE) { 
              Element e = (Element)thisNode; 
              if (e.getAttribute("status").equals("donotcontact")) {
                   return NodeFilter.FILTER_REJECT; 
              }  
         } 
         return NodeFilter.FILTER_ACCEPT; 
    } 
}
 现在,该应用程序运行后,整个元素(包括其子元素)都不见了:清单 8. 拒绝一个 Node 的结果
   employee (empid="332" status="contact" ) :
        deptid () : 24
        shift () : night
        name () : Jenny Berman
   employ

解决方案 »

  1.   

    XML's DOM Level 2 Traversal module provides two new objects, the TreeWalker and the NodeIterator, which simplify the process of navigating a Document. More than that, the module defines a NodeFilter, which can be used to programmatically control what nodes are visible to the TreeWalker or NodeFilter. This tip shows you how to create a NodeFilter as well as a Traversal object that uses it.
    Note: This tip uses JAXP, but the sample application will also work with Xerces-Java 2, and the concepts are applicable for any XML parser environment. The source code
    This tip creates an application that traverses a simple XML document that contains information on which employees to contact in case of emergency:Listing 1. The source document
    <?xml version="1.0"?>
    <personnel>
       <employee empid="332" status="contact">
            <deptid>24</deptid>
            <shift>night</shift>
            <name>Jenny Berman</name>
       </employee>
       <!-- Other employees listed here -->
    </personnel>
     Ultimately, the application counts on the NodeFilter to eliminate employees with a status value of donotcontact.Traversing the tree
    The Document Object Model Level 2 Traversal Module defines objects that walk the tree of an XML document, displaying information about the current Node. The entire process of creating a TreeWalker is described in the tip Traversing an XML document with a TreeWalker, but for convenience, consider this application which displays the elements of the employee document:Listing 2. Creating the TreeWalker
    import javax.xml.parsers.DocumentBuilder;
    import javax.xml.parsers.DocumentBuilderFactory;
    import java.io.File;
    import org.w3c.dom.Document;
    import org.w3c.dom.DOMImplementation;
    import org.w3c.dom.Node;
    import org.w3c.dom.traversal.DocumentTraversal;
    import org.w3c.dom.traversal.TreeWalker;
    import org.w3c.dom.traversal.NodeIterator;
    import org.w3c.dom.traversal.NodeFilter;
    import org.w3c.dom.NamedNodeMap;
    import org.w3c.dom.Element;public class ShowDocument {    public static void main (String args[]) {
           File docFile = new File("employees.xml");
                    
           Document doc = null;
           try {
              DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
              DocumentBuilder db = dbf.newDocumentBuilder();
            
              doc = db.parse(docFile);
           } catch (Exception e) {
               System.out.print("Problem parsing the file.");
           }       DOMImplementation domimpl = doc.getImplementation();
           if (domimpl.hasFeature("Traversal", "2.0")) {           Node root = doc.getDocumentElement();
               int whattoshow = NodeFilter.SHOW_ALL;
              NodeFilter nodefilter = null; 
               boolean expandreferences = false;           DocumentTraversal traversal = (DocumentTraversal)doc;
      
               TreeWalker walker = traversal.createTreeWalker(root, 
                                                              whattoshow, 
                                                              nodefilter, 
                                                              expandreferences);
               Node thisNode = null;
               thisNode = walker.nextNode();
               while (thisNode != null) {
                  if (thisNode.getNodeType() == thisNode.ELEMENT_NODE) {
                     System.out.print(thisNode.getNodeName() + " ");
                     Element thisElement = (Element)thisNode;
                     NamedNodeMap attributes = thisElement.getAttributes();
                     System.out.print("(");
                     for (int i = 0; i < attributes.getLength(); i++) {
                        System.out.print(attributes.item(i).getNodeName() + "=\"" +
                                         attributes.item(i).getNodeValue() + "\" ");
                     }
                     System.out.print(") : ");
                  } else if (thisNode.getNodeType() == thisNode.TEXT_NODE) {
                     System.out.print(thisNode.getNodeValue());
                  }
                  thisNode = walker.nextNode();
              }        } else {
               System.out.println("The Traversal module isn't supported.");
            }
       }
    }
     
      

  2.   

    When the TreeWalker traverses the Document tree, it displays Element names, attributes, and Text Nodes:Listing 3. The application output -- all nodes
    personnel () :
       employee (empid="332" status="contact" ) :
            deptid () : 24
            shift () : night
            name () : Jenny Berman   employee (empid="994" status="donotcontact" ) :
            deptid () : 24
            shift () : day
            name () : Andrew Fule   employee (empid="948" status="contact" ) :
            deptid () : 3
            shift () : night
            name () : Anna Bangle
     Notice that one of the parameters passed on the creation of the TreeWalker is a NodeFilter object that has been set to null. The result is that the TreeWalker sees all of the Nodes of the Document that satisfy the whattoshow value, NodeFilter.SHOW_ALL.Creating a NodeFilter
    Creating a NodeFilter object gives you fine-grained control over the Nodes that are seen by the TreeWalker object. All that's required is a class that implements the NodeFilter interface, which consists of a single method, acceptNode(). When the TreeWalker encounters a Node, it passes it to the acceptNode() method to determine whether the Node is acceptable or not. Because this is a custom class, you can base that judgment on anything you can pack into an application. In this case, the judgment is based on the value of the status attribute:Listing 4. Implementing the NodeFilter
    import org.w3c.dom.traversal.NodeFilter;
    import org.w3c.dom.Node;
    import org.w3c.dom.Element;public class EmployeeFilter implements NodeFilter {     public short acceptNode(Node thisNode) { 
             if (thisNode.getNodeType() == Node.ELEMENT_NODE) { 
                  Element e = (Element)thisNode; 
                  if (e.getAttribute("status").equals("donotcontact")) {
                       return NodeFilter.FILTER_SKIP; 
                  }  
             } 
             return NodeFilter.FILTER_ACCEPT; 
        } 

     Each Node is checked to see if it's an Element. If it is, the status attribute (if any) is checked. The filter skips all elements with a status attribute of donotcontact while accepting everything else.All that's necessary now is to create the TreeWalker with the new NodeFilter object:Listing 5. Setting the TreeWalker to see the NodeFilter
    ...
               Node root = doc.getDocumentElement();
               int whattoshow = NodeFilter.SHOW_ALL;
               NodeFilter nodefilter = new EmployeeFilter(); 
               boolean expandreferences = false;           DocumentTraversal traversal = (DocumentTraversal)doc;
      
               TreeWalker walker = traversal.createTreeWalker(root, 
                                                              whattoshow, 
                                                              nodefilter, 
                                                              expandreferences);
    ...
     Now when the TreeWalker traverses the Document, it checks each Node against the EmployeeFilter object, so it skips the Node that contains a status attribute of donotcontact:Listing 6. The results
    personnel () :
       employee (empid="332" status="contact" ) :
            deptid () : 24
            shift () : night
            name () : Jenny Berman
            deptid () : 24
            shift () : day
            name () : Andrew Fule   employee (empid="948" status="contact" ) :
            deptid () : 3
            shift () : night
            name () : Anna Bangle Notice that the employee element is missing, but its children are not. In some cases, such as this application, this isn't what you really want. Instead of skipping a Node, you want to reject it altogether.FILTER_SKIP vs. FILTER_REJECT
    When a TreeWalker skips a Node, it moves on to the next Node encountered. In some cases, this is a child of the original. For this application, you're trying to eliminate employees who shouldn't be contacted, so rather than just skipping the employee element, you want to reject that element and all of its children. You can do this easily by changing the NodeFilter to use FILTER_REJECT instead of FILTER_SKIP: Listing 7. Rejecting a Node
    ...
             if (thisNode.getNodeType()==Node.ELEMENT_NODE) { 
                  Element e = (Element)thisNode; 
                  if (e.getAttribute("status").equals("donotcontact")) {
                       return NodeFilter.FILTER_REJECT; 
                  }  
             } 
             return NodeFilter.FILTER_ACCEPT; 
        } 
    }
     Now when the application runs, the entire element (including its children) is missing:Listing 8. Results of rejecting a Node
       employee (empid="332" status="contact" ) :
            deptid () : 24
            shift () : night
            name () : Jenny Berman
       employee (empid="948" status="contact" ) :
            deptid () : 3
            shift () : night
            name () : Anna Bangle It's important to note that the TreeWalker is able to skip the entire Element because it understands the inherent parent-child relationships. A NodeIterator, on the other hand, sees the document in a flattened way, much like a SAX stream, and has no concept of parents or children. If you were to create a NodeIterator rather than a TreeWalker, FILTER_REJECT would act the same as FILTER_SKIP.Summary
    The Traversal module defines TreeWalkers and NodeIterators that look to an external NodeFilter object to determine which Nodes are visible. This enables you to create an application in which the available data can be controlled from outside the main application. A Node can be skipped, in which case the next Node is processed, or it can be rejected, in which case all of its children are also hidden from the main application.
      

  3.   

    谢谢 leon1999(城市迷途) 
    kreven(天地无用恨离别) 你贴的都是E文看起来太累!不过还是谢谢!