使用Java中的XPATH处理分层XML文档。效率?

时间:2010-12-16 06:57:38

标签: java xml xpath wikimedia-dumps

现在已经多次询问过这个问题的变体,但我的问题更多的是在Java中使用XPATH的一般效率问题。

我的任务:获取有关地理位置的维基百科文章,并从中创建分层数据结构。

我已经获得了维基页面的XML版本,并根据具有直观意义的架构重新格式化。我还创建了一系列非常简单的类来表示不同级别的管理层次结构,例如:

public class Province implements java.io.Serializable {

private ArrayList<City> cities = new ArrayList<City>();
private String hanzi;
private String pinyin;


public Province(String hanzi, String pinyin) {
this.hanzi = hanzi;
this.pinyin = pinyin;
}

除了添加城市的方法,一些getter和setter方法,以及toString()。

以下是我正在处理的XML文件类型的示例:

<mediawiki>
     <page>
           <title>Tianjin</title>
           <revision>
                    <id>2064019</id>
                    <text xml:space="preserve">
                              <province>
                                       <hanzi>天津</hanzi>
                                       <pinyin>Tianjin</pinyin>

                                       <Level2>
                                               <hanzi>和平</hanzi>
                                               <pinyin>Heping</pinyin>
                                               <zip>300000</zip>
                                       </Level2>

                                       <Level2>
                                                <hanzi>河东</hanzi>
                                                <pinyin>Hedong</pinyin>
                                                <zip>300000</zip>
                                        </Level2>

                                </province>
                    </text>
            </revision>
      </page>

...

</mediawiki>

此时我基本上有一个功能设置,但代码非常重复,并没有考虑地理数据固有的分层性质。理想情况下,我可以停留在某个级别(让我们说“专注于某一特定省份”),并且仅从相关的角度来指代那些事情,以最小化我必须遍历整个文档的次数。作为一个例子(请注意,我使用的是传统文档设置的抽象,但下面的方法几乎完全符合传统方法):

XPathReader reader = new XPathReader("sourceXML\\Provinces.xml");           
String expression = "/mediawiki/page";
NodeList allProvinces = (NodeList)reader.read(expression, XPathConstants.NODESET);

for(int i=0; i < allProvinces.getLength(); i++) {
     expression = "/mediawiki/page[" + i + "]/revision/text/province/hanzi";
     String hanzi = reader.read(expression, XPathConstants.STRING).toString();

     expression = "/mediawiki/page[" + i + "]/revision/text/province/pinyin";
     String pinyin = reader.read(expression, XPathConstants.STRING).toString();

     Province currProv = new Province(hanzi, pinyin);         



     expression = "/mediawiki/page[" + i + "]/revision/text/province/Level2";
     NodeList level2 = (NodeList)reader.read(expression, XPathConstants.NODESET);

     for(int j=1; j < level2.getLength(); j++) {
           expression = "/mediawiki/page[" + i + "]/revision/text/province/Level2[" + j + "]/hanzi";
           String hanzi2 = reader.read(expression, XPathConstants.STRING).toString();   

           expression = "/mediawiki/page[" + i + "]/revision/text/province/Level2[" + j + "]/pinyin";
           String pinyin2 = reader.read(expression, XPathConstants.STRING).toString();  

         City currCity = new City(hanzi2, pinyin2);
         currProv.add(currCity);
...
     }
}   
坦率地说,这看起来很愚蠢。我没有考虑到这样一个事实,即一旦我达到我关注的水平,这些字符串的所有内容都是相同的。我没有引用任何类型的相对路径,每当我遍历文档的一部分时,我实际上遍历整个事物。如果我可以暂时阻止原始XML文档的其余部分并且只关注我的省份,那将是很好的,从而相对而言是指所有相关的东西。

我应该特别注意“读取”抽象背后的成本有多贵:

xPath.compile(expression);
String result = xPathExpression.evaluate (xmlDocument, returnType);

我基本上是在重新编译相同的模式,结尾略有不同?加载感兴趣的部分,然后用“currProv / hanzi”之类的东西引用它的孩子怎么样?

我已经研究过解析XML的其他方法,而“Digester”似乎做了类似于我想要的事情http://commons.apache.org/digester/core.html,但我已经拥有了这个XPATH实现中的几乎所有东西。

我有一种唠叨的怀疑,即这个问题的解决方案非常简单......但我无法完全掌握解决方案。无论如何,我感谢你的时间!

1 个答案:

答案 0 :(得分:1)

相对嵌套的XPath是要走的路。

我领导EclipseLink JAXB实现(MOXy),我们通过@XmlPath注释提供此功能。如果你已经有了XPath,那将是一个相对容易的映射。

有关详细信息,请参阅: