簡體   English   中英

StaX解析:Transformer.transform方法自動移動光標,但並不總是很好

[英]StaX parsing: Transformer.transform method moves cursor automatically, not always nice

我正在使用XMLStreamReader來實現我的目標(拆分xml文件)。 看起來不錯,但仍然無法達到預期效果。 我的目標是從輸入文件中拆分每個節點“ nextTag”:

<?xml version="1.0" encoding="UTF-8"?>
<firstTag>
    <nextTag>1</nextTag>
    <nextTag>2</nextTag>
</firstTag>

結果應如下所示:

<?xml version="1.0" encoding="UTF-8"?><nextTag>1</nextTag>
<?xml version="1.0" encoding="UTF-8"?><nextTag>2</nextTag>

使用Java引用Split 1GB Xml文件,我通過以下代碼實現了我的目標:

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.StringWriter;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamReader;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stax.StAXSource;
import javax.xml.transform.stream.StreamResult;

public class Demo4 {

    public static void main(String[] args) throws Exception {

        InputStream inputStream = new FileInputStream("input.xml");
        BufferedReader in = new BufferedReader(new InputStreamReader(inputStream));

        XMLInputFactory factory = XMLInputFactory.newInstance();
        TransformerFactory tf = TransformerFactory.newInstance();
        Transformer t = tf.newTransformer();

        XMLStreamReader streamReader = factory.createXMLStreamReader(in);

        while (streamReader.hasNext()) {
            streamReader.next();

            if (streamReader.getEventType() == XMLStreamReader.START_ELEMENT
                    && "nextTag".equals(streamReader.getLocalName())) {

                StringWriter writer = new StringWriter();
                t.transform(new StAXSource(streamReader), new StreamResult(
                        writer));
                String output = writer.toString();
                System.out.println(output);

            }

        }

    }

}

其實很簡單。 但是,我的輸入文件是單行形式的:

<?xml version="1.0" encoding="UTF-8"?><firstTag><nextTag>1</nextTag><nextTag>2</nextTag></firstTag>

我的Java代碼不再產生所需的輸出,而是僅產生以下結果:

 <?xml version="1.0" encoding="UTF-8"?><nextTag>1</nextTag>

花了幾個小時后,我很確定已經找到了原因:

 t.transform(new StAXSource(streamReader), new StreamResult(writer));

這是因為在執行了transform方法之后,光標將自動移至下一個事件。 在代碼中,我有以下部分:

while (streamReader.hasNext()) {
    streamReader.next();
                      ...
        t.transform(new StAXSource(streamReader), new StreamResult(writer));
                      ...
}

第一次轉換后,streamReader直接獲得2次next():

 1. from the transform method
 2. from the next method in the while loop

因此,在使用這種特定的行XML的情況下,游標永遠無法獲得第二個open標簽。 相反,如果輸入XML具有漂亮的打印形式,則可以從游標到達第二個,因為第一個結束標記后有一個空格事件

不幸的是,我找不到任何設置方法,因此在執行transform方法后,translator不會自動跳至下一個事件。 這真令人沮喪。

有人知道我該如何處理嗎? 從語義上也很受歡迎。 非常感謝。

問候,

拉特納

PS。 我肯定可以寫出解決此問題的方法(在轉換它之前先漂亮地打印xml文檔,但這意味着輸入xml之前已被修改,這是不允許的)

如前所述,如果元素節點彼此直接跟隨,則轉換步驟將繼續執行下一個create元素。

為了解決這個問題,您可以使用嵌套的while循環來重寫代碼,如下所示:

        while(reader.next() != XMLStreamConstants.END_DOCUMENT) {
            while(reader.getEventType() == XMLStreamConstants.START_ELEMENT && reader.getLocalName().equals("nextTag")) {
                StringWriter writer = new StringWriter();
                // will transform the current node to a String, moves the cursor to the next START_ELEMENT
                t.transform(new StAXSource(reader), new StreamResult(writer)); 
                System.out.println(writer.toString());
            }
        }

如果您的xml文件適合存儲在內存中,則可以在JOOX庫的幫助下進行嘗試,該庫以導入:

compile 'org.jooq:joox:1.3.0'

和主類一樣:

import java.io.File;
import java.io.IOException;
import org.joox.JOOX;
import org.joox.Match;
import org.w3c.dom.Document;
import org.xml.sax.SAXException;

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

import static org.joox.JOOX.$;

public class Main {

    public static void main(String[] args) 
            throws IOException, SAXException, TransformerException {
        DocumentBuilder builder = JOOX.builder();
        Document document = builder.parse(new File(args[0]));

        Transformer transformer = 
                TransformerFactory.newInstance().newTransformer();
        transformer.setOutputProperty("omit-xml-declaration", "no");

        final Match $m = $(document);
        $m.find("nextTag").forEach(tag -> {
            try {
                transformer.transform(
                        new DOMSource(tag), 
                        new StreamResult(System.out));
                System.out.println();
            }
            catch (TransformerException e) {
                System.exit(1);
            }
        });

    }
}

它產生:

<?xml version="1.0" encoding="UTF-8"?><nextTag>1</nextTag>
<?xml version="1.0" encoding="UTF-8"?><nextTag>2</nextTag>

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM