Vtd-xml获取元素的子节点和文本

时间:2016-03-11 07:28:00

标签: xml vtd-xml

<RmtInf>
    <Strd>
        <RfrdDocInf>
            <Tp>
                <CdOrPrtry>
                    <Cd>CINV</Cd>
                </CdOrPrtry>
            </Tp>
            <Nb>3501870</Nb>
        </RfrdDocInf>
        <RfrdDocInf>
            <Tp>
                <CdOrPrtry>
                    <Prtry>AGJ</Prtry>
                </CdOrPrtry>
            </Tp>
            <Nb>10090187000155438</Nb>
        </RfrdDocInf>
        <RfrdDocAmt>
            <DuePyblAmt Ccy="SEK">5453.29</DuePyblAmt>
        </RfrdDocAmt>
    </Strd>
    <Strd>
        <RfrdDocInf>
            <Tp>
                <CdOrPrtry>
                    <Cd>CINV</Cd>
                </CdOrPrtry>
            </Tp>
            <Nb>160120</Nb>
        </RfrdDocInf>
        <RfrdDocInf>
            <Tp>
                <CdOrPrtry>
                    <Prtry>AGJ</Prtry>
                </CdOrPrtry>
            </Tp>
            <Nb>10090187000155438</Nb>
        </RfrdDocInf>
        <AddtlRmtInf>/ARI/</AddtlRmtInf>
    </Strd>
</RmtInf>   
 while (ap.evalXPath() != -1)
    {
    if (vn.toElement(VTDNav.FIRST_CHILD, "AmtDtls")) {

    do {
        amtDetails = getXpathValue(vn, ".//TxAmt/Amt/text()");
        // System.out.println("amtDetails:::" + amtDetails);
        if (amtDetails != null)
            creditNotification.setAmount(new BigDecimal(amtDetails));
    } while (vn.toElement(VTDNav.NEXT_SIBLING, "AmtDtls"));

    }   

        vn.push();

        // System.out.println("transIndex::" + transIndex);
        ap1.selectXPath("/Document/BkToCstmrDbtCdtNtfctn/Ntfctn/Ntry/NtryDtls/TxDtls[" + transIndex
                + "]/RmtInf/Strd");

        while (ap1.evalXPath() != -1) {
            // System.out.println("sCount::::"+sCount);
            custInvType = getXpathValue(vn, "RfrdDocInf[1]/Tp/CdOrPrtry/Cd/text()");
            // System.out.println("custInvType:::" + custInvType);
            creditNotificationFlag = false;
            if (custInvType != null
                    && custInvType.equalsIgnoreCase(IBS2BankConstants.TYPE_DEBITCREDITNOTIFICATION_CINV)) {
                kidNmbr = getXpathValue(vn, "RfrdDocInf[1]/Nb/text()");
                // System.out.println("\tskidNmbr::::" + kidNmbr);
                // added as an required by IBS team
                creditNotification.setMemo3(kidNmbr);

                if (kidNmbr != null) {
                    creditNotification.setKid(kidNmbr);

                    if (kidNmbr.matches("^\\d{18}")) {
                        creditNotification
                                .setCustomerNumber(IBS2BankUtility.getKidsCustomerNumber(kidNmbr));

                        // logger.debug("custNumber:::" +
                        // custNumber);
                        creditNotification.setInvoiceNumber(IBS2BankUtility.getKidsInvoiceNumber(kidNmbr));
                        // logger.debug("custInvoice:::" +
                        // custInvoice);
                    } else if (kidNmbr.matches("^\\d{10}")) {

                        creditNotification.setInvoiceNumber(IBS2BankUtility.getKidsInvoiceNumber(kidNmbr));

                    }
                }

            }

            String prtryCodeType = getXpathValue(vn, "RfrdDocInf[2]/Tp/CdOrPrtry/Prtry/text()");
            // System.out.println("prtryCodeType :::" +
            // prtryCodeType);
            if (prtryCodeType != null
                    && prtryCodeType.equalsIgnoreCase(IBS2BankConstants.PROPRIETARY_CODE_AGJ)) {
                // added as an required by IBS team
                creditNotification.setMemo4(getXpathValue(vn, "RfrdDocInf[2]/Nb/text()"));
            }

            credNotificationList.add(creditNotification);

        }
        ap1.resetXPath();

        vn.pop();

    }

我更新了xml,代码Push()用于保存当前位置的状态,第二次使用是因为RmtInf有多个Strd,我想遍历它。现在上面的代码可以工作,但是解析xml文件大小为600 MB需要花费很多时间。

1 个答案:

答案 0 :(得分:0)

首先,你的文档的嵌套级别非常深,如果你做了大量的xpath,我建议你打开VTDGen的set LC level方法并将其设置为5(默认为3)...

因为你的doc明显低于2GB的限制,考虑切换到标准的vtd-xml(你有大约1GB的内存吗?)。尽管它没有内存映射功能,但它可以更好地调整性能。

要选择更深层的索引级别,请调用VTDGen的selectLcDepth(int i)并将i设置为5.

我注意到的另一件事是你的代码

getXpathValue(vn, ".//TxAmt/Amt/text())

我建议你将选择xpath表达式逻辑移出xpath评估循环,而不是在循环之前的代码中进行xpath编译......它看起来像......

   Autopilot ap_temp = new AutoPilot(vn);
    ap_tmp.selectXPath("..//TxAmt/Amt/text()");
    ...
    int i=-1;
    while((i=ap.evalXPath())!=-1){

       ...
       //amtDetails = getXpathValue(vn, ".//TxAmt/Amt/text()"); will be replaced by
       amtDetails = getXpathValue(vn, ap_temp);

此外,如果amtDetails是一个字符串,你可以直接使用evalXPathToString()这样的东西直接将输出转换为字符串......

你的代码有多个selectXPath,我怀疑杀死的性能,你应该尝试将它们带出循环...

我前一段时间写了一篇博客.. .https://ximpleware.wordpress.com/2015/10/12/performance-tuning/

推送和弹出的位置似乎是错误的。具体来说,push()应该在主逻辑中的代码之前立即...我很惊讶您的代码按照您的指示运行...

您是否注意到有两个巨大的XPath评估循环相互嵌套?这看起来不太好......

总的来说,我认为你已经创建了一段代码,旨在以非常低效的方式运行。

这是我现在的建议......

期待您的想法和评论。

要使代码正常工作,你需要在循环中使用vtd-xml游标...我假设你也知道你需要在while循环中保持节点位置,以免影响xpath的正确性评价...

您的代码可能看起来像这样...

VTDNav vn = vg.getNav();
...
while (ap.evalXPath() != -1) { 

     if (vn.toElement(VTDNav.FIRSTCHILD)){
              System.out.println(" node name ===>"+vn.toRawString(vn.getCurrentIndex()));
              vn.toElement(VTDNav.PARENT);
     }
}