仅使用XPath在VTD-XML中进行动态查找

仅使用XPath在VTD-XML中进行动态查找,xml,xpath,vtd-xml,Xml,Xpath,Vtd Xml,我试图使用XPath表达式在VTD-XML中查找引用当前元素的元素。假设我的XML包含书籍和评级,如下所示: <root> <book id="1" name="Book1"/> <book id="2" name="Book1"/> <rating book-id="1" value="5"/> <rating book-id="2" value="3"/> </root> @Test public vo

我试图使用XPath表达式在VTD-XML中查找引用当前元素的元素。假设我的XML包含书籍和评级,如下所示:

<root>
  <book id="1" name="Book1"/>
  <book id="2" name="Book1"/>
  <rating book-id="1" value="5"/>
  <rating book-id="2" value="3"/>
</root>
@Test
public void xpathReference() throws Exception {
    byte[] bytes = ("<root>\n"
                 + "  <book id=\"1\" name=\"Book1\"/>\n"
                 + "  <book id=\"2\" name=\"Book1\"/>\n"
                 + "  <rating book-id=\"1\" value=\"5\"/>\n"
                 + "  <rating book-id=\"2\" value=\"3\"/>\n"
                 + "  <rating book-id=\"3\" value=\"4\"/>\n"
                 + "</root>").getBytes();

    VTDGen vtdGenerator = new VTDGen();
    vtdGenerator.setDoc(bytes);
    vtdGenerator.parse(true);
    VTDNav vtdNavigator = vtdGenerator.getNav();

    AutoPilot autoPilot = new AutoPilot(vtdNavigator);
    autoPilot.selectXPath("//*/rating[./@book-id=//book/@id]/@value");
    int id;
    int count = 0;
    while ((id = autoPilot.evalXPath()) != -1) {
        String elementName = vtdNavigator.toString(id);
        int text = vtdNavigator.getAttrVal(elementName);
        String txt = text != -1 ? vtdNavigator.toNormalizedString(text) : "";
        System.out.println("Found match at ID " + id + " in field name '" + elementName + "' with value '" + txt + "'");
        count++;
    }
    System.out.println("Total number of matches: " + count);
    assertThat(count, is(equalTo(2)));
}
这不起作用,因为current()函数是XSLT独有的。因此,我尝试声明一个名为“current”to“.”的变量表达式来表示“thecurrentbook”,但这也不起作用,因为(顾名思义),变量表达式不存储表达式的结果,而是存储表达式本身

在VTD-XML中,是否有一种方法可以仅使用XPath表达式来实现这种效果? (我意识到在代码中有各种各样的方法,但我想使用纯XPath,这样用户就可以轻松地创建一个描述其数据格式的配置文件)

编辑:
接受答案的结果是,我想要的不能使用单个XPath表达式。最后,我添加了一个选项,这样用户就可以指定如何找到当前图书的唯一标识符(即“/@id”或“/isbn”)。然后,我的代码执行此表达式并用结果替换评级搜索XPath中的某些占位符(例如“$$”)。

类似于
/*/rating[./@book id=///book/@id]/@value的XPath表达式应仅检索与可用图书id匹配的评级值

如果将
添加到XML文档中,XPath将只返回Book1和Book2的值
5
3
,因为没有ID为3的书籍可用

VTD的简单测试方法如下所示:

<root>
  <book id="1" name="Book1"/>
  <book id="2" name="Book1"/>
  <rating book-id="1" value="5"/>
  <rating book-id="2" value="3"/>
</root>
@Test
public void xpathReference() throws Exception {
    byte[] bytes = ("<root>\n"
                 + "  <book id=\"1\" name=\"Book1\"/>\n"
                 + "  <book id=\"2\" name=\"Book1\"/>\n"
                 + "  <rating book-id=\"1\" value=\"5\"/>\n"
                 + "  <rating book-id=\"2\" value=\"3\"/>\n"
                 + "  <rating book-id=\"3\" value=\"4\"/>\n"
                 + "</root>").getBytes();

    VTDGen vtdGenerator = new VTDGen();
    vtdGenerator.setDoc(bytes);
    vtdGenerator.parse(true);
    VTDNav vtdNavigator = vtdGenerator.getNav();

    AutoPilot autoPilot = new AutoPilot(vtdNavigator);
    autoPilot.selectXPath("//*/rating[./@book-id=//book/@id]/@value");
    int id;
    int count = 0;
    while ((id = autoPilot.evalXPath()) != -1) {
        String elementName = vtdNavigator.toString(id);
        int text = vtdNavigator.getAttrVal(elementName);
        String txt = text != -1 ? vtdNavigator.toNormalizedString(text) : "";
        System.out.println("Found match at ID " + id + " in field name '" + elementName + "' with value '" + txt + "'");
        count++;
    }
    System.out.println("Total number of matches: " + count);
    assertThat(count, is(equalTo(2)));
}

根据注释,上面的代码没有以类似于迭代的方式提取当前处理的书籍的数据。下面的代码现在尝试实现这一点:

@Test
public void xpathReference() throws Exception {
    byte[] bytes = ("<root>\n"
                    + "  <book id=\"1\" name=\"Book1\"/>\n"
                    + "  <book id=\"2\" name=\"Book2\"/>\n"
                    + "  <book id=\"4\" name=\"Book3\"/>\n"
                    + "  <rating book-id=\"1\" value=\"5\"/>\n"
                    + "  <rating book-id=\"2\" value=\"3\"/>\n"
                    + "  <rating book-id=\"3\" value=\"4\"/>\n"
                    + "</root>").getBytes();

    VTDGen vtdGenerator = new VTDGen();
    vtdGenerator.setDoc(bytes);
    vtdGenerator.parse(true);
    VTDNav vtdNavigator = vtdGenerator.getNav();

    AutoPilot autoPilot = new AutoPilot(vtdNavigator);
    autoPilot.selectXPath("//book/@id");
    int id;
    int count = 0;
    while ((id = autoPilot.evalXPath()) != -1) {
        String elementName = vtdNavigator.toString(id);
        int bookId_id = vtdNavigator.getAttrVal(elementName);
        String bookId = bookId_id != -1 ? vtdNavigator.toNormalizedString(bookId_id) : "";

        AutoPilot xpathBookName = new AutoPilot(vtdNavigator);
        xpathBookName.selectXPath("//book[@id=" + bookId + "]/@name");
        String bookName = xpathBookName.evalXPathToString();

        AutoPilot xpathRating = new AutoPilot(vtdNavigator);
        xpathRating.selectXPath("//rating[@book-id=" + bookId + "]/@value");
        String bookRating = xpathRating.evalXPathToString();

        if ("".equals(bookRating)) {
            System.out.println("Book " + bookName + " with id " + bookId + " has no rating yet");
        } else {
            System.out.println("Book " + bookName + " with id " + bookId + " has a rating of " + bookRating);
        }
        count++;
    }
    System.out.println("Total number of matches: " + count);
    assertThat(count, is(equalTo(3)));
}
请注意,我确实稍微更新了您第二本书的名称,以便您可以更容易地看到差异


。。。是的,用Java代码获取当前书籍的id,然后用它构造一个XPath表达式是很容易的,但是正如我所解释的,我希望用户能够使用XPath定义他们的文档格式,所以我不希望代码中有任何特定于格式的内容

VTD只支持XPath 1.0。如果您(或您的客户机)能够提出XPath1.0查询,那么您也应该能够通过VTD提取相应的值。我想,普通XPath查询的表达能力不足以直接交付所需内容


由于该示例对于您所需的用例来说可能过于简单,因此很难就如何设计应用程序来处理此类场景给出任何建议。也许可以用更详细的例子更新你的问题。处理此问题的一个简单方法是引入必须单独定义的占位符变量,然后在尝试执行此类XPath表达式时点击此类占位符,只需将这些占位符替换为以前提取的值的具体值。

谢谢您的回答,但是我想你忽略了我在反复阅读书籍,并且只使用XPath来获得当前书籍的评级这一事实。(是的,用Java代码获取当前书籍的id,然后用它构造一个XPath表达式是很容易的,但正如我所解释的,我希望用户能够使用XPath定义他们的文档格式,所以我不希望代码中有任何特定于格式的内容)@zwets更新帖子以使用当前处理的书籍,以便提取名称和评级银行!我采用了类似于您在帖子中建议的方法,基本上实现了我自己的变量系统。顺便说一句,只是一个建议,但是你可以在你的答案的顶部加一个简短的注释,归结为“不,这不可能,但是请看下面的建议”。不,我的问题已经回答了。明天我将发送一个后续消息,并附上这篇文章的链接。顺便说一下,感谢VTD-XML,它太棒了!
Book Book1 with id 1 has a rating of 5
Book Book2 with id 2 has a rating of 3
Book Book3 with id 4 has no rating yet
Total number of matches: 2