关于java:如何使用STAX事件驱动或流API解析未知的XML结构

How to Parse unknown XML structure using STAX Event Driven Or Stream API

我尝试使用dom解析未知的XML结构并获得成功,但现在我尝试使用stax事件或流解析器,因为XML文件很大。虽然我使用sax进行此操作并获得成功。但现在我对stax有点好奇。现在我真的想了解它。

我对此做了一些研究并编写了这个代码

这是Stax流媒体

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public static void main(String args[]) throws XMLStreamException, FileNotFoundException {
    XMLInputFactory xf = XMLInputFactory.newInstance();

    XMLStreamReader xsr = xf.createXMLStreamReader(new InputStreamReader(new FileInputStream("c:\\file.xml")));
    XMLInputFactoryImpl x = new XMLInputFactoryImpl();
    while (xsr.hasNext()) {

        int e = xsr.next();

        if (e == XMLStreamConstants.START_ELEMENT) {
            System.out.println("Element Start Name:" + xsr.getLocalName());
        }
        if (e == XMLStreamReader.END_ELEMENT) {
            System.out.println("Element End Name:" + xsr.getLocalName());
        }
        if (e == XMLStreamConstants.CHARACTERS) {
            System.out.println("Element Text:" + xsr.getText());
        }
    }
}

和Stax事件驱动

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
   public static void main(String[] args) throws XMLStreamException, FileNotFoundException {
        // TODO code application logic here
        // TODO Auto-generated method stub

        XMLInputFactory xif = XMLInputFactory.newInstance();
        XMLEventReader xer = xif.createXMLEventReader(new InputStreamReader(new FileInputStream("c:\\file.xml")));

        while (xer.hasNext()) {

            XMLEvent e = xer.nextEvent();
            if (e.isCharacters()) {
                System.out.println("Element Text :"+e.asCharacters().getData());
            }
            if (e.isStartElement()) {
                System.out.println("Start Element :"+e.asStartElement().getName());
            }
            if (e.isEndElement()) {
                System.out.println("End Element :"+e.asEndElement().getName());
            }
        }
    }

}

在上述两个代码中,父节点还打印空白文本,但不应该因为XML子节点只包含文本,而只应打印子节点文本。例如

1
2
3
4
5
6
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<student id="1">
  <fname>TestFirstName</fname>
  <lname>TestLastName</lname>
  <sectionname rollno="1">A</sectionname>
</student>

它应该打印testFirstName、testLastname等,这意味着如果父节点要打印字符(e==xmlstreamConstants.characters),或者如果父节点要打印字符(e.isCharacters()),它不应该返回true。因此,我如何修改我的代码来解析XML文件的任何级别,它可能在任何深度或任何层叠级别上。


这是我使用Stax流的解决方案

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public static void main(String[] args) throws FileNotFoundException, XMLStreamException {
    XMLInputFactory xf=XMLInputFactory.newInstance();
    XMLStreamReader xsr=xf.createXMLStreamReader(new InputStreamReader(new FileInputStream("c:\\test.xml")));
    String startElement = null;
    String endElement  =null;
    String elementTxt = null;
    while (xsr.hasNext()) {
        int e = xsr.next();
        if(e==XMLStreamConstants.START_ELEMENT){
            //System.out.println("StartElement Name :" + xsr.getLocalName());
            startElement = xsr.getLocalName();
        }
        if(e==XMLStreamConstants.END_ELEMENT){
            //System.out.println("EndElement Name :" + xsr.getLocalName());
            endElement = xsr.getLocalName();
            if(startElement.equalsIgnoreCase(endElement))
            System.out.println(" ElementName :"+ startElement +" ElementText :" + elementTxt);
        }
        if(e==XMLStreamConstants.CHARACTERS){
            //System.out.println("Element TextValue :" + xsr.getText());
            elementTxt = (xsr.getText().contains("
"
)) ?"" : xsr.getText();
        }

    }
}

这是我使用Stax事件的解决方案

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public static void main(String[] args) throws XMLStreamException,FileNotFoundException {
    // TODO code application logic here
    // TODO Auto-generated method stub

    XMLInputFactory xif = XMLInputFactory.newInstance();
    XMLEventReader xer = xif.createXMLEventReader(new InputStreamReader(new FileInputStream("c:\\test.xml")));
    String startElement = null;
    String endElement = null;
    String elementTxt = null;
    while (xer.hasNext()) {

        XMLEvent e = xer.nextEvent();
        if (e.isCharacters()) {
            elementTxt = (e.asCharacters().getData().contains("
"
)) ?"": e.asCharacters().getData();
        }
        if (e.isStartElement()) {
            // System.out.println("Start Element :"+e.asStartElement().getName());
            startElement = e.asStartElement().getName().toString();
        }
        if (e.isEndElement()) {
            // System.out.println("End Element :"+e.asEndElement().getName());
            endElement = e.asEndElement().getName().toString();
            if (startElement.equalsIgnoreCase(endElement))
                System.out.println(" ElementName :" + startElement +" ElementText :" + elementTxt);
        }
    }
}

事件分析序列是正确的,您有对空字符的调用,因为有漂亮的打印格式(空格或制表符)。如果您的XML是线性(平面)的,那么您将不会有这些额外的事件。

从stax文档中,您可以看到"可忽略的空白和重要的空白也被报告为字符事件。":您只需要去掉空白。这样可以添加测试!e.asCharacters().isWhiteSpace()

1
2
3
4
XMLEvent e = xer.nextEvent();
if (e.isCharacters() && !e.asCharacters().isWhiteSpace()) {
    System.out.println("Element Text :"+e.asCharacters().getData());
}

这应该过滤掉空白空间,只有你预期的事件。