VTD-XML - невозможно получить текст после тега span

<?xml version="1.0"?>
<catalog>
    <book id="bk001" type='fiction'>
        <author>Gambardella, Matthew</author>
        <author>Doe, John</author>
        <title>XML IN-DEPT Developer's Guide</title>
        <genre>Computer</genre>
        <price>44.95</price>
        <snippet>
            <inlineXML contenttype="application/xhtml+xml" >
                <html lang="en-US" >
                    <head>
                        <title>XML IN-DEPT Developer's Guide</title>
                    </head>
                    <body>
                        <p>This is an example book for developers want to gain knowledge on  <span class="boldcls" type="xml" >XML</span> Marshalling and UnMarshalling. Need to know all about <span class="boldcls" type="tech" >XML parsing and editing</span>, Grab this Book!</p>
                    </body>
                </html>
            </inlineXML>
        </snippet>
    </book>
</catalog>

Выше приведен пример XML, я хочу оценить выражение XPath "/book/snippet", перебрать все элементы и получить текст. Я использую этот ( /questions/15621431/razobrat-xml-fajl-ispolzuya-vtd-xml/15621439#15621439) модифицированный код (как в ОБНОВЛЕНИИ ниже), используя библиотеку VTD-XML, но проблема в том, что он не получает текст после того, как встретит span тег. Итак, вывод, который я получаю сейчас для тега абзаца:

    Level [6] Tag [p]   
            This is an example book for developers want to gain knowledge on
    Level [7] Tag [span] @class=boldcls
            XML
    Level [8] Tag [span] @class=boldcls
            XML parsing and editing

Что не так, как и должно быть:

    Level [6] Tag [p]   
            This is an example book for developers want to gain knowledge on XML Marshalling and UnMarshalling. Need to know all about XML parsing and editing, Grab this Book!
    Level [7] Tag [span] @class=boldcls
            XML
    Level [8] Tag [span] @class=boldcls
            XML parsing and editing

ОБНОВЛЕНИЕ: я немного изменил пример кода:

package com.vtd.test;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.w3c.dom.Document;

import com.ximpleware.AutoPilot;
import com.ximpleware.NavException;
import com.ximpleware.VTDGen;
import com.ximpleware.VTDNav;
import com.ximpleware.XPathEvalException;
import com.ximpleware.XPathParseException;

public class VTDXMLReader {

    // private String xpathExpression;

    private VTDNav vtdNav;

    private AutoPilot autoPilot;

    private boolean includeAttributes;

    private String attribute;

    public VTDXMLReader(final Document storyDoc, final boolean includeAttributes, final String xpathExpression) {
        this.includeAttributes = includeAttributes;
        // this.xpathExpression = xpathExpression;
        final VTDGen vtdGen = new VTDGen();
        try {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            TransformerFactory transformerFactory = TransformerFactory.newInstance();
            Transformer transformer = transformerFactory.newTransformer();
            DOMSource source = new DOMSource(storyDoc);
            StreamResult result = new StreamResult(baos);
            transformer.transform(source, result);
            byte[] array = baos.toByteArray();

            vtdGen.setDoc(array);
            vtdGen.parse(true);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        vtdNav = vtdGen.getNav();
        autoPilot = new AutoPilot(vtdNav);
        String[] xpathFrags = xpathExpression.split("/");
        if (xpathFrags[xpathFrags.length - 1].startsWith("@")) {
            attribute = xpathFrags[xpathFrags.length - 1].replaceAll("@", "");
        }
        try {
            autoPilot.selectXPath(xpathExpression);
        } catch (XPathParseException e) {
            e.printStackTrace();
        }
    }

    public List<String> readXML() throws IOException {
        List<String> values = new ArrayList<String>();
        try {
            while (autoPilot.evalXPath() != -1) {
                // printTag(vn);
                if (includeAttributes) {
                    Map<String, String> amap = new LinkedHashMap<String, String>();

                    loadAttributeMap(vtdNav, amap);

                    for (String aname : amap.keySet()) {
                        String aval = amap.get(aname);
                        values.add(aval);
                        // System.out.print(" @" + aname + "=" + aval);
                    }
                    // System.out.print("\n");
                }
                int val = 0;
                if (attribute != null && !attribute.isEmpty()) {
                    val = vtdNav.getAttrVal(attribute);
                    if (val != -1) {
                        String id = vtdNav.toNormalizedString(val);
                        values.add(id);
                        // System.out.println("Attribute: " + id);
                    }
                }
                val = vtdNav.getText();
                if (val != -1) {
                    String author = vtdNav.toNormalizedString(val);
                    values.add(author);
                    // System.out.println("\t" + author);
                }
                navigateToChildren(vtdNav, includeAttributes, values);

            }
            // autoPilot.resetXPath();
        } catch (Exception ex) {
            ex.printStackTrace();
        }

        return values;

    }

    public static void navigateToChildren(final VTDNav vn, final boolean includeAttributes, List<String> values) {
        try {
            vn.push();
            if (vn.toElement(VTDNav.FIRST_CHILD)) {
                do {
                    // printTag(vn);

                    if (includeAttributes) {
                        Map<String, String> amap = new LinkedHashMap<String, String>();

                        loadAttributeMap(vn, amap);

                        for (String aname : amap.keySet()) {
                            String aval = amap.get(aname);
                            values.add(aval);
                            // System.out.print(" @" + aname + "=" + aval);
                        }
                        // System.out.print("\n");
                    }

                    int val = vn.getText();
                    if (val != -1) {
                        String author = vn.toNormalizedString(val);
                        values.add(author);
                        // System.out.println("\t" + author);
                    }
                    navigateToChildren(vn, includeAttributes, values);
                } while (vn.toElement(VTDNav.NEXT_SIBLING));
            }
            vn.toElement(VTDNav.PARENT);
            vn.pop();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static void loadAttributeMap(VTDNav nav, Map<String, String> amap) {

        nav.push();

        try {
            AutoPilot apAtt = new AutoPilot(nav);
            apAtt.selectXPath("@*");

            int j = -1;
            while ((j = apAtt.evalXPath()) != -1) {
                String name = nav.toString(j);
                String val = nav.toString(j + 1);

                amap.put(name, val);
            }
        } catch (XPathParseException | XPathEvalException | NavException e) {
            e.printStackTrace();
        }

        nav.pop();
    }

    public static void main(String[] args) {
        try {
            DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
            DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
            Document document = dBuilder.parse(new File("books.xml"));

            VTDXMLReader vtdxmlReader = new VTDXMLReader(document, false, "/catalog/book/snippet");
            List<String> xmlFrags = vtdxmlReader.readXML();
            for (String xmlFrag : xmlFrags) {
                System.out.println(xmlFrag);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

Вывод вышеуказанного кода:

XML IN-DEPT Developer's Guide
This is an example book for developers want to gain knowledge on
XML
XML parsing and editing

Который должен был быть:

XML IN-DEPT Developer's Guide
This is an example book for developers want to gain knowledge on
XML
Marshalling and UnMarshalling. Need to know all about
XML parsing and editing
, Grab this Book!

Есть идеи?

Что я хочу сделать: если следующий тег абзаца в HTML-документе:

<p>This is an example book for developers want to gain knowledge on  <span class="boldcls" type="xml" >XML</span> Marshalling and UnMarshalling. Need to know all about <span class="boldcls" type="tech" >XML parsing and editing</span>, Grab this Book!</p>

Я хочу написать Reader, который читает его слева направо, включая значения атрибутов, например, следующую строку:

==> This is an example book for developers want to gain knowledge on
==> boldcls xml XML
==> Marshalling and UnMarshalling. Need to know all about
==> boldcls tech XML parsing and editing
==> , Grab this Book!

В настоящее время я делаю это с помощью XMLEventReader, который я хочу заменить на код библиотеки VTD-XML.

1 ответ

Решение

Я сделал небольшой мод для вашей подпрограммы navigateToChildren... Я вызвал VTDNav getXPathStringVal(), чтобы получить все текстовые узлы... в основном, проблема в getText(), который отлично работает для ориентированных на данные XML-документов... для ориентированных на документы использования В некоторых случаях вы должны вызывать метод getXPathStringVal() для непосредственного извлечения текстового узла... этот метод доступен в более новой версии vtd-xml. Это то, что вы ищите?

public static void navigateToChildren(final VTDNav vn, final boolean includeAttributes, List<String> values) {
        try {
            vn.push();
            if (vn.toElement(VTDNav.FIRST_CHILD)) {
                do {
                    //printTag(vn);

                    if (includeAttributes) {
                        Map<String, String> amap = new LinkedHashMap<String, String>();

                        loadAttributeMap(vn, amap);

                        for (String aname : amap.keySet()) {
                            String aval = amap.get(aname);
                            values.add(aval);
                            System.out.print(" ==>@" + aname + "=" + aval);
                        }
                        // System.out.print("\n");
                    }

                    int val = vn.getText();

                    if (val != -1) {
                        String author = vn.getXPathStringVal();
                        values.add(author);
                        System.out.println("==>\t" + author);
                    }
                    navigateToChildren(vn, includeAttributes, values);
                } while (vn.toElement(VTDNav.NEXT_SIBLING));
            }
            vn.toElement(VTDNav.PARENT);
            vn.pop();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

Второе редактирование: я написал небольшое приложение, которое выполняет весь подчиненный текст и сцепление атрибутов... в основном оно обращается к нижележащим буферам VTD напрямую, используя значение индекса... и сканирует записи VTD последовательно. Если тип токена - attr val или символьные данные, приложение добавляет его в строковый буфер...

import com.ximpleware.*;

public class collectTokens {
    public static void main(String[] s) throws VTDException{
        VTDGen vg = new VTDGen();
        if (!vg.parseFile("d:\\xml\\books.xml", true)){
            return;
        }
        VTDNav vn = vg.getNav();
        AutoPilot ap = new AutoPilot(vn);
        ap.selectXPath("/catalog/book/snippet/inlineXML/html/body/p");
        int i=ap.evalXPath();
        // i points to the p element node
        if (i!=-1){
            int j = vn.getCurrentIndex();// get the token index of p
            int d = vn.getTokenDepth(j);
            int count = vn.getTokenCount();
            int index=j+1;
            // collect the text of all text and attr vals  sequentially
            StringBuilder sb = new StringBuilder(50);
            while((index<count)){
                if (vn.getTokenDepth(index)==d 
                        && vn.getTokenDepth(index)== VTDNav.TOKEN_STARTING_TAG)
                    break;
                if (vn.getTokenType(index)== VTDNav.TOKEN_CHARACTER_DATA
                        || vn.getTokenType(index)==VTDNav.TOKEN_ATTR_VAL){
                            sb.append(vn.toString(index)+" ");
                        }
                index++;
            }
            System.out.println(sb);
        }
    }
}
Другие вопросы по тегам