19

次のような形式の 1000 エントリ ドキュメントがあります。

<Example>
     <Entry>
          <n1></n1>
          <n2></n2>
      </Entry>
      <Entry>
          <n1></n1>
          <n2></n2>
      </Entry>
      <!--and so on-->

ここには 1000 を超えるエントリ ノードがあります。基本的にすべてのノードを1つずつ取得し、各ノードで分析を行うJavaプログラムを作成しています。しかし、問題は、ノードの検索時間がその数とともに増加することです。たとえば、最初のノードを取得するのに 78 ミリ秒かかり、2 番目のノードを取得するのに 100 ミリ秒かかり、増加し続けます。また、999 個のノードを取得するには 5 秒以上かかります。これは非常に遅いです。このコードを、1000 を超えるエントリを持つ XML ファイルにプラグインします。数百万のような人もいます。ドキュメント全体を解析する合計時間は 5 分以上です。

この単純なコードを使用してトラバースしています。これは、 xpathnxpからノードを取得するためのすべてのメソッドを備えた独自のクラスです。

nxp.fromXpathToNode("/Example/Entry" + "[" + i  + "]", doc);    

ファイルのdocドキュメントです。i取得するノードの番号です。

また、私がこのようなことをしようとすると

List<Node> nl = nxp.fromXpathToNodes("/Example/Entry",doc);  
      content = nl.get(i);    

私は同じ問題に直面しています。

ノードの tretirival を高速化する方法については誰もが解決策を持っているため、XML ファイルから 1 番目のノードと 1000 番目のノードを取得するのに同じ時間がかかります。


xpathtonode のコードは次のとおりです。

public Node fromXpathToNode(String expression, Node context)  
{  
    try  
    {  
        return (Node)this.getCachedExpression(expression).evaluate(context, XPathConstants.NODE);  
    }  
    catch (Exception cause)  
    {  
        throw new RuntimeException(cause);  
    }  
}  

fromxpathtonodes のコードは次のとおりです。

public List<Node> fromXpathToNodes(String expression, Node context)  
{  
    List<Node> nodes = new ArrayList<Node>();  
    NodeList results = null;  
    
    try  
    {  
        results = (NodeList)this.getCachedExpression(expression).evaluate(context, XPathConstants.NODESET);  
          
        for (int index = 0; index < results.getLength(); index++)  
        {  
            nodes.add(results.item(index));  
        }  
    }  
    catch (Exception cause)  
    {  
        throw new RuntimeException(cause);  
    }  
    
    return nodes;  
}  

そしてここからがスタート

public class NativeXpathEngine implements XpathEngine  
{      
private final XPathFactory factory;  
  
private final XPath engine;  

/**
 * Cache for previously compiled XPath expressions. {@link XPathExpression#hashCode()}
 * is not reliable or consistent so use the textual representation instead.
 */  
private final Map<String, XPathExpression> cachedExpressions;  
  
public NativeXpathEngine()  
{
    super();  
    
    this.factory = XPathFactory.newInstance();  
    this.engine = factory.newXPath();  
    this.cachedExpressions = new HashMap<String, XPathExpression>();  
}  
4

6 に答える 6

10

VTD-XML を試してください。DOM よりも少ないメモリを使用します。SAX よりも使いやすく、XPath をサポートしています。開始するのに役立つサンプル コードを次に示します。XPath を適用して Entry 要素を取得し、n1 および n2 子要素を出力します。

final VTDGen vg = new VTDGen();
vg.parseFile("/path/to/file.xml", false);

final VTDNav vn = vg.getNav();
final AutoPilot ap = new AutoPilot(vn);
ap.selectXPath("/Example/Entry");
int count = 1;
while (ap.evalXPath() != -1) {
    System.out.println("Inside Entry: " + count);

    //move to n1 child
    vn.toElement(VTDNav.FIRST_CHILD, "n1");
    System.out.println("\tn1: " + vn.toNormalizedString(vn.getText()));

    //move to n2 child
    vn.toElement(VTDNav.NEXT_SIBLING, "n2");
    System.out.println("\tn2: " + vn.toNormalizedString(vn.getText()));

    //move back to parent
    vn.toElement(VTDNav.PARENT);
    count++;
}
于 2010-08-10T12:18:02.757 に答える
7

正しい解決策は、次のように、item(i) を呼び出した直後にノードをデタッチすることです。

Node node = results.item(index)
node.getParentNode().removeChild(node)
nodes.add(node)

複数の呼び出しでXPath.evaluateのパフォーマンスが (異常に) 低下する

于 2013-02-27T00:55:13.910 に答える
4

Xpath Evaluation で同様の問題が発生しました。以前に使用された XPathApi よりも 100 倍高速な CachedXPathAPI を使用してみました。この API の詳細については、http: //xml.apache.org/xalan-j/apidocs/org/apache/xpath/CachedXPathAPI.htmlを参照してください。

それが役に立てば幸い。乾杯、マドゥスダン

于 2012-03-12T12:05:21.363 に答える
2

巨大でフラットなドキュメントを解析する必要がある場合は、SAX が優れた代替手段です。巨大な DOM を構築する代わりに、XML をストリームとして扱うことができます。あなたの例は、次のような ContentHandler を使用して解析できます。

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.ext.DefaultHandler2;

public class ExampleHandler extends DefaultHandler2 {

    private StringBuffer chars = new StringBuffer(1000);

    private MyEntry currentEntry;
    private MyEntryHandler myEntryHandler;

    ExampleHandler(MyEntryHandler myEntryHandler) {
        this.myEntryHandler = myEntryHandler;
    }

    @Override
    public void characters(char[] ch, int start, int length)
            throws SAXException {
        chars.append(ch);
    }

    @Override
    public void endElement(String uri, String localName, String qName)
            throws SAXException {
        if ("Entry".equals(localName)) {
            myEntryHandler.handle(currentEntry);
            currentEntry = null;
        }
        else if ("n1".equals(localName)) {
            currentEntry.setN1(chars.toString());
        }
        else if ("n2".equals(localName)) {
            currentEntry.setN2(chars.toString());
        }
    }


    @Override
    public void startElement(String uri, String localName, String qName,
            Attributes atts) throws SAXException {
        chars.setLength(0);
        if ("Entry".equals(localName)) {
            currentEntry = new MyEntry();
        }
    }
}

ドキュメントの構造がより深く複雑な場合は、スタックを使用してドキュメント内の現在のパスを追跡する必要があります。次に、汎用の ContentHandler を作成して汚い作業を行い、ドキュメントの種類に依存するハンドラーで使用することを検討する必要があります。

于 2010-03-02T19:54:33.027 に答える
1

どのようなパーサーを使用していますか?

DOM はドキュメント全体をメモリにプルします。ドキュメント全体をメモリにプルすると、操作は高速になりますが、Web アプリまたは for ループでこれを行うと影響が生じる可能性があります。

SAX パーサーは、要求に応じてオンデマンドで解析し、ノードをロードします。

したがって、ニーズに合ったパーサー実装を使用してみてください。

于 2010-03-02T17:33:52.003 に答える
0

xpath にはJAXENライブラリを 使用します: http://jaxen.codehaus.org/

于 2010-03-02T17:43:26.537 に答える