Dengues Studio: Google Group:http://groups.google.com/group/dengues; QQ Group:24885404.
          解析一個(gè)XML文件有很多方法,最常用的就是Dom4j,和JDOM.這個(gè)我們就是講使用Xalan來解析一個(gè)XML文件.
          先有個(gè)xml文件如下:
          <?xml version="1.0" encoding="UTF-8"?>
          <a:main xmlns="test0" xmlns:a="testt" xmlns:b="test2">
              
          <a:node>
                  
          <a:nodeA1>A1</a:nodeA1>
                  
          <a:nodeA2>
                      
          <b:nodeB>B1</b:nodeB>
                      
          <b:nodeB>B2</b:nodeB>
                  
          </a:nodeA2>
              
          </a:node>
              
          <node>
                  
          <nodeD/>
              
          </node>
          </a:main> 
          這個(gè)一個(gè)簡單的xml文件.但是我們現(xiàn)在要用xpath來查找
          "/a:main/node"
          一般你是一個(gè)很復(fù)雜的表達(dá)式,這個(gè)xpath是經(jīng)過簡化的.簡化的代碼你可以使用如下:
           1 private static String simplifyXPathExpression(String xpathExpression) {
           2 
           3         Perl5Matcher matcher = new Perl5Matcher();
           4 
           5         Perl5Compiler compiler = new Perl5Compiler();
           6 
           7         Pattern pattern = null;
           8         try {
           9             pattern = compiler.compile("(.*)/\\s*\\w+\\s*(/(\\.\\.|parent))(.*)");
          10         } catch (MalformedPatternException e) {
          11             ExceptionHandler.process(e);
          12         }
          13 
          14         Perl5Substitution substitution = new Perl5Substitution("$1$4", Perl5Substitution.INTERPOLATE_ALL);
          15 
          16         int lengthOfPreviousXPath = 0;
          17 
          18         do {
          19             lengthOfPreviousXPath = xpathExpression.length();
          20             if (matcher.matches(xpathExpression, pattern)) {
          21                 xpathExpression = Util.substitute(matcher, pattern, substitution, xpathExpression, Util.SUBSTITUTE_ALL);
          22             }
          23         } while (xpathExpression.length() != lengthOfPreviousXPath);
          24 
          25         return xpathExpression;
          26     }
          這里使用的org.apache.oro.text.regex包里面的類.
          現(xiàn)在就開始解析一個(gè)XML文件:在Dengues 項(xiàng)目中的org.dengues.commons.jdk.xpath.ComplexXPathUsedXalan類.
           1 public ComplexXPathUsedXalan(String xmlFilename) {
           2         xmlInput = new File(xmlFilename);
           3         if (!xmlInput.exists()) {
           4             throw new RuntimeException("Specified file does not exist!");
           5         }
           6         try {
           7             DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
           8             docFactory.setNamespaceAware(true);
           9             DocumentBuilder builder = docFactory.newDocumentBuilder();
          10             document = builder.parse(xmlInput);
          11             initLastNodes(document.getDocumentElement());
          12             prefixToNamespace.put(XMLConstants.XML_NS_PREFIX, XMLConstants.XML_NS_URI);
          13         } catch (ParserConfigurationException e) {
          14             e.printStackTrace();
          15         } catch (IOException e) {
          16             e.printStackTrace();
          17         } catch (SAXException exception) {
          18             exception.printStackTrace();
          19         }
          20         XPathFactory factory = XPathFactory.newInstance();
          21         xPath = factory.newXPath();
          22         xPath.setNamespaceContext(getNamespaceContext());
          23     }
          這是類的構(gòu)造函數(shù).這里要注意的幾個(gè)地方就是:1.第8行設(shè)置這個(gè)DocFactory支持Namespace.這里一定要設(shè)置否則你將不能找所需要的節(jié)點(diǎn).
          2.在第12行,此前我新建了一個(gè)Map用來存儲(chǔ)Prefix和Namespace的對應(yīng)關(guān)系:
          1 private final Map<String, String> prefixToNamespace = new HashMap<String, String>();
          在12行就是講XML對應(yīng)Namespace設(shè)置進(jìn)去.
          3.第11行,它的作用的就是取出所有的Prefix和Namespace.代碼如下:
           1 private void initLastNodes(Node node) {
           2         NodeList childNodes = node.getChildNodes();
           3         int length = childNodes.getLength();
           4         int type = node.getNodeType();
           5         if (type == Node.ELEMENT_NODE) {
           6             setPrefixToNamespace(node);
           7         }
           8         for (int i = 0; i < length; i++) {
           9             Node item = childNodes.item(i);
          10             if (item.getChildNodes().getLength() > 0) {
          11                 initLastNodes(item);
          12             }
          13         }
          14     }
          15 
          16     /**
          17      * DOC qzhang Comment method "setPrefixToNamespace".
          18      * 
          19      * @param node
          20      */
          21     private void setPrefixToNamespace(Node node) {
          22         NamedNodeMap nnm = node.getAttributes();
          23         for (int i = 0; i < nnm.getLength(); i++) {
          24             Node attr = nnm.item(i);
          25             String aname = attr.getNodeName();
          26             boolean isPrefix = aname.startsWith(XMLConstants.XMLNS_ATTRIBUTE + ":");
          27             if (isPrefix || aname.equals(XMLConstants.XMLNS_ATTRIBUTE)) {
          28                 int index = aname.indexOf(':');
          29                 String p = isPrefix ? aname.substring(index + 1) : XMLConstants.NULL_NS_URI;
          30                 prefixToNamespace.put(p, attr.getNodeValue());
          31             }
          32         }
          33     }
          這樣的就可以去到當(dāng)前XML的所有Prefix的所有節(jié)點(diǎn).
          4.其實(shí)去Prefix和Namepace還由另外的API:com.sun.org.apache.xml.interal.utils.PrefixResloverDefault,你可以使用它:
          1  PrefixResolverDefault resolverDefault = new PrefixResolverDefault(document.getDocumentElement());
          2        String namespace = resolverDefault.getNamespaceForPrefix(prefix);
          你可以使用這種方法.但是我覺得這種方法在大部分情況下解決不了問題.原因:(1)當(dāng)前你只有document的根結(jié)點(diǎn).也就是說它只能得到根結(jié)點(diǎn)定義的Namespace.(2)當(dāng)根結(jié)點(diǎn)也使用了Namespace的話(a:main),解析就有問題.
          5.構(gòu)造函數(shù)的22行設(shè)置一個(gè)NamespaceContext,代碼如下:
           1 private NamespaceContext getNamespaceContext() {
           2         return new NamespaceContext() {
           3 
           4             public String getNamespaceURI(String prefix) {
           5                 String namespaceForPrefix = getNamespaceForPrefix(prefix);
           6                 return namespaceForPrefix;
           7 
           8             }
           9 
          10             public java.util.Iterator getPrefixes(String val) {
          11                 return null;
          12             }
          13 
          14             public String getPrefix(String uri) {
          15                 return null;
          16             }
          17         };
          18     }
          19 
          20     /**
          21      * DOC qzhang Comment method "getNamespaceForPrefix".
          22      * 
          23      * @param prefix
          24      * @return
          25      */
          26     protected String getNamespaceForPrefix(String prefix) {
          27         String namespace = prefixToNamespace.get(prefix);
          28         if (namespace != null) {
          29             return namespace;
          30         }
          31         return getDefaultNamespace();
          32     }
          33 
          34     private String getDefaultNamespace() {
          35         Node parent = document.getDocumentElement();
          36         int type = parent.getNodeType();
          37         if (type == Node.ELEMENT_NODE) {
          38             NamedNodeMap nnm = parent.getAttributes();
          39             for (int i = 0; i < nnm.getLength(); i++) {
          40                 Node attr = nnm.item(i);
          41                 String aname = attr.getNodeName();
          42                 if (aname.equals(XMLConstants.XMLNS_ATTRIBUTE)) {
          43                     return attr.getNodeValue();
          44                 }
          45             }
          46         }
          47         return XMLConstants.NULL_NS_URI;
          48     }
          這個(gè)總要就是取Namespace值,但是當(dāng)你輸入Prefix不在Map里面的時(shí)候,它將取默認(rèn)的Namespace,也就是在getDefaultNamespace().
          現(xiàn)在就是最后要提供一個(gè)API:
           1 public Object parseXPath(String expression, QName name) {
           2         try {
           3             expression = addDefaultPrefix(expression);
           4             XPathExpression xexpr = xPath.compile(expression);
           5             Object cd = xexpr.evaluate(getDocumnent(), name);
           6             return cd;
           7         } catch (XPathExpressionException e) {
           8             e.printStackTrace();
           9         }
          10         return null;
          11     }
          12 
          13     private String addDefaultPrefix(String xPathExpression) {
          14         if (XMLConstants.NULL_NS_URI.equals(getDefaultNamespace())) {
          15             return xPathExpression;
          16         } else {
          17             StringBuilder expr = new StringBuilder();
          18             String[] split = xPathExpression.split("/");
          19             for (String string : split) {
          20                 if (!string.equals(""&& string.indexOf(':'== -1 && string.indexOf('.'== -1) {
          21                     expr.append(XMLConstants.DEFAULT_NS_PREFIX + ":");
          22                 }
          23                 expr.append(string + "/");
          24             }
          25             if (split.length > 0) {
          26                 expr.deleteCharAt(expr.length() - 1);
          27             }
          28             return expr.toString();
          29         }
          30     }

          這個(gè)就是提供的解析xpath表達(dá)是的接口.大家會(huì)看到了要執(zhí)行一個(gè)添加addDefaultPrefix()的函數(shù),它的作用就是在
          當(dāng)存在默認(rèn)Namespace的時(shí)候,添加一個(gè)默認(rèn)的Prefix.這樣的問題解決了.
          再看看測試的代碼:
           1 private static void testXPath() {
           2         ComplexXPathUsedXalan complexXPath = new ComplexXPathUsedXalan("c:/SimpleNamespace.xml");
           3         String expression = "/a:main/node";
           4         try {
           5             NodeList nodes = (NodeList) complexXPath.parseXPath(expression, XPathConstants.NODESET);
           6             System.out.println("length: " + nodes.getLength());
           7             for (int i = 0; i < nodes.getLength(); i++) {
           8                 Node item = nodes.item(i);
           9                 System.out.println("Name:" + item.getNodeName() + " value:" + item.getNodeValue());
          10             }
          11         } catch (Exception e) {
          12             e.printStackTrace();
          13         }
          14     }
          這樣就可以得到打印結(jié)果:
          1 length: 1
          2 Name:node value:null
          就是這樣了.歡迎大家指正.



          Dengues論壇(http://groups.google.com/group/dengues/),一個(gè)很好的Eclipse開發(fā)者樂園.

          Feedback

          # re: [Dengues]關(guān)于使用XPath的勸解.帶有Namespace的.  回復(fù)  更多評論   

          2007-11-06 16:46 by zDevil(Dengues Studio)
          不好意思,標(biāo)題都寫錯(cuò)了,應(yīng)該是講解.^_^!

          # re: [Dengues]關(guān)于使用XPath的勸解.帶有Namespace的.  回復(fù)  更多評論   

          2007-11-06 17:41 by li
          恰好今天在項(xiàng)目中也用到dom4j和jaxen,不過在Xpath時(shí)候遇到不能能解析命名空間的的問題,沒有好的辦法就去掉了命名空間,呵呵
          以后重新試試

          只有注冊用戶登錄后才能發(fā)表評論。


          網(wǎng)站導(dǎo)航:
           
          Dengues Studio: Google Group:http://groups.google.com/group/dengues; QQ Group:24885404.
          主站蜘蛛池模板: 商南县| 莱芜市| 新沂市| 揭东县| 万年县| 永靖县| 阜新市| 兰西县| 盐源县| 贡觉县| 阿合奇县| 夏河县| 当阳市| 昌邑市| 左云县| 南投县| 荥经县| 土默特右旗| 通化市| 托里县| 嘉祥县| 内江市| 无锡市| 安岳县| 抚顺市| 孟津县| 隆昌县| 宜宾县| 波密县| 正宁县| 阳曲县| 隆尧县| 大洼县| 镇赉县| 邯郸县| 布尔津县| 璧山县| 乐山市| 永定县| 怀远县| 汉中市|