【问题标题】:Java VTD-XML and XPath: Use XPath in found sectionJava VTD-XML 和 XPath:在找到的部分使用 XPath
【发布时间】:2019-02-18 23:54:21
【问题描述】:

我有以下 XML 文件:

<project>
    <category type="Files">
        <type name="File" type="String" id="1">
            <field name="Name" type="String">
                <value type="String"><![CDATA[Smile.JPG]]></value>
            </field>
            <multiValue name="Entries" type="FileEntry">
                <model type="Specs" state="Intact">
                    <field name="Value" type="String">
                        <value type="String"><![CDATA[10241624]]></value>
                    </field>
                  </model>
            </multiValue>
        </type>
        <type name="File" type="String" id="2">
            <field name="Name" type="String">
                <value type="String"><![CDATA[OldMan.JPG]]></value>
            </field>
            <multiValue name="Entries" type="FileEntry">
                <model type="Specs" state="Gone">
                    <field name="Category" type="String">
                        <value type="String"><![CDATA[Size]]></value>
                    </field>
                    <field name="Value" type="String">
                        <value type="String"><![CDATA[821563412]]></value>
                    </field>
                </model>
            </multiValue>
        </type>
    </category>
</project>

java 代码 sn-p:(仅用于隔离问题的代码)

VTDGen vg = new VTDGen();
int i;
AutoPilot ap = new AutoPilot();
ap.selectXPath("/project/category[@type=\"Files\"]");
AutoPilot ap2 = new AutoPilot();
BookMark bm = new BookMark();

vg.parseFile("stackoverflow_example.xml", false);

VTDNav vn = vg.getNav();
ap.bind(vn);
ap2.bind(vn);

/* main XPath selection */
ap.selectXPath("/project/category[@type=\"Files\"]");

/* part 1 */
//XPath eval returns one node at a time
ap2.selectXPath("type[@name=\"File\"]/field/value/text()");
while ((i = ap.evalXPath()) != -1) {
    bm.recordCursorPosition(); // equivalent to vn.push();
    int j;
    while ((j = ap2.evalXPath()) != -1) {
            logger.debug(" NAME ==> " + vn.toString(j));
    }
    ap2.resetXPath();
    bm.setCursorPosition(); // equivalent to vn.pop();
}
ap.resetXPath();

/* part 2 */
ap2.selectXPath("type[@name=\"File\"]/multiValue/model[@type=\"Specs\"]/field[@name=\"Value\"]/value/text()");
while ((i = ap.evalXPath()) != -1) {
    bm.recordCursorPosition(); // equivalent to vn.push();
    int j;
    while ((j = ap2.evalXPath()) != -1) {
        logger.debug(" SIZE ==> " + vn.toString(j));
    }
    ap2.resetXPath();
    bm.setCursorPosition(); // equivalent to vn.pop();
}
ap.resetXPath();

在找到名为 File 的类型的一个部分后,我想从该部分获取文件名和大小。 (当然,稍后会更多,但根据我的理解,这就足够了)。

现在代码的问题是,它确实找到了匹配的值,但 SIZE 不是文件中的子项。

输出:

NAME ==> Smile.JPG
NAME ==> OldMan.JPG

SIZE ==> 10241624
SIZE ==> 821563412

我有两个 AutoPilot,一个用于主要部分,我想用第二个 AutoPilot 进行内部搜索。

任何人都可以帮助仅在第一个找到的部分中“搜索”吗?我想要一些输出,例如:

NAME ==> Smile.JPG
SIZE ==> 10241624

NAME ==> OldMan.JPG
SIZE ==> 821563412

【问题讨论】:

    标签: java xpath vtd-xml


    【解决方案1】:

    至少在我对 VTD-XML 的理解中,您的示例代码至少有 2 个 IMO 问题。首先,对文件名和大小的 xpath 查询对我来说似乎很奇怪,因为它们不包含像 /// 这样的根。接下来,最好提取文件 ID 并将它们添加到 XPath 查询中。

    我拿了你的代码并稍微调整了一下

    import com.ximpleware.AutoPilot;
    import com.ximpleware.VTDGen;
    import com.ximpleware.VTDNav;
    import java.io.File;
    import java.lang.invoke.MethodHandles;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    public class StackOverflowExample {
    
      private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
    
      public static void main(String ... args) throws Exception {
        VTDGen vg = new VTDGen();
    
        File testFile = new File(StackOverflowExample.class.getResource("/stackoverflow_example.xml").toURI());
        vg.parseFile(testFile.getAbsolutePath(), false);
    
        VTDNav vn = vg.getNav();
        AutoPilot ap = new AutoPilot();
        ap.bind(vn);
        AutoPilot ap2 = new AutoPilot();
        ap2.bind(vn);
    
        // iterate over all file IDs
        int i;
        ap.selectXPath("//category[@type=\"Files\"]/type/@id");
        while ((i = ap.evalXPath()) != -1) {
          int j;
    
          // retrieve the value of the id attribute field
          String attributeName = vn.toString(i);
          int attributeId = vn.getAttrVal(attributeName);
          String attributeVal = vn.toString(attributeId);
    
          // add the id value to the respective xpath query
          ap2.selectXPath("//category[@type=\"Files\"]/type[@name=\"File\" and @id=\"" + attributeVal + "\"]/field/value/text()");
          while ((j = ap2.evalXPath()) != -1) {
            LOG.debug(" NAME ==> " + vn.toString(j));
          }
          ap2.resetXPath();
    
          ap2.selectXPath("//category[@type=\"Files\"]/type[@name=\"File\" and @id=\"" + attributeVal + "\"]/multiValue/model[@type=\"Specs\"]/field[@name=\"Value\"]/value/text()");
          while ((j = ap2.evalXPath()) != -1) {
            LOG.debug(" SIZE ==> " + vn.toString(j));
          }
          ap2.resetXPath();
        }
        ap.resetXPath();
      }
    }
    

    产生以下输出

    11:57:07.196 [main] DEBUG StackOverflowExample -  NAME ==> Smile.JPG
    11:57:07.201 [main] DEBUG StackOverflowExample -  SIZE ==> 10241624
    11:57:07.202 [main] DEBUG StackOverflowExample -  NAME ==> OldMan.JPG
    11:57:07.204 [main] DEBUG StackOverflowExample -  SIZE ==> 821563412
    

    请注意,如果您使用像 /project/category[@type="Files"]/type/@id 这样的 XPath 查询而不是 //category[@type="Files"]/type/@id,则只会列出第一个值文件元素。不确定为什么 VTD-XML 不会遍历所有元素。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-05-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-02-22
      相关资源
      最近更新 更多