【问题标题】:Vtd-xml to get sub nodes and text of an elementvtd-xml 获取元素的子节点和文本
【发布时间】:2016-03-11 07:28:00
【问题描述】:
<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()用于保存当前位置的状态,第二个while用于RmtInf有多个Strd,我想遍历它。现在上面的代码可以工作了,但是解析 xml 文件需要很长时间,文件大小为 600 MB。

【问题讨论】:

  • 请编辑您的帖子,而不是添加其他信息作为评论。
  • 您可以编辑您的帖子,以便我可以更轻松地查看您的 java 代码吗?
  • 你能发布你的 getXpathValue() 例程代码吗?
  • 我有几个问题: 1. 为什么第二个 evaluateXPath() 路由用 push() 和 pop() 包装? 2.似乎在第一个循环中,退出循环时光标位置重置为原始位置?你那里有一些一致性问题......
  • @user2861637-- 我仍在等待您在回答部分对我的 cmets 的反馈...

标签: xml vtd-xml


【解决方案1】:

首先,你文档的嵌套层级比较深,如果你做的xpaths比较大,建议你开启VTDGen的set LC level方法,设置为5(默认为3)...

因为您的文档明显小于 2GB 的限制,请考虑切换到标准 vtd-xml(您有大约 1GB 的可用内存吗?)。尽管它没有内存映射功能,但它的性能得到了更好的调整。

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

我注意到的另一件事是在您的代码中

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

我建议您将 select 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 和 pop 的位置好像不对。具体来说,push() 应该紧跟在主逻辑中的代码之前...我很惊讶您的代码可以按照您的指示工作...

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

总的来说,我认为您创建了一段代码,其运行效率非常低。

这是我目前的建议……

期待你的想法和cmets。

要使代码正常工作,您需要在循环内使用 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);
     }
} 

【讨论】:

  • 我已经添加了代码你能看看我哪里弄错了@vtd-xml-author
  • 以及如何添加VTDGen的set LC level方法
猜你喜欢
  • 2011-08-25
  • 2022-08-05
  • 1970-01-01
  • 1970-01-01
  • 2015-02-20
  • 1970-01-01
  • 2021-12-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多