Java VTD-XML и XPath: используйте XPath в найденном разделе - PullRequest
0 голосов
/ 19 февраля 2019

У меня есть следующий 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: (просто код, чтобы изолировать проблему)

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();

И после нахождения одного раздела типа сИмя файла, я хочу получить имя файла и размер из этого раздела.(Конечно, чуть позже, но, на мой взгляд, этого было бы достаточно).

Проблема с кодом заключается в том, что он находит совпадающие значения, но SIZE не является дочерним.из файла.

Вывод:

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

SIZE ==> 10241624
SIZE ==> 821563412

У меня есть два автопилота, один для основного раздела, и у меня была идея выполнить внутренний поиск со вторым автопилотом.

Кто-нибудь может помочь только «поиск» в первом найденном разделе?Я хотел бы иметь вывод, например:

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

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

1 Ответ

0 голосов
/ 19 февраля 2019

Ваш пример кода имеет как минимум 2 проблемы IMO, по крайней мере, в моем понимании VTD-XML.Во-первых, запросы xpath для имени и размера файла кажутся мне странными, поскольку они не содержат корень, такой как / или //.Далее, было бы предпочтительнее извлечь идентификаторы файлов и добавить их в запросы 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

Обратите внимание, что если вы используете запрос XPath, такой как /project/category[@type="Files"]/type/@id вместо //category[@type="Files"]/type/@id, будет указан только первый элемент файла значений.Не уверен, почему VTD-XML не выполняет итерацию по всем элементам.

...