使用sax,stax或DOM将XML转换为java中的数据结构

时间:2014-11-16 18:07:00

标签: java xml dom xml-parsing stax

所以我在过去两周一直在研究我的这个项目,而且我没有取得任何进展。我的问题不是开始解析XML文件,而是之后如何处理它。所以我用SAX,StAX和DOM解析器制作了程序,我在其中获取了一个非常大的XML文件,然后按顺序打印出元素及其值。但是,我处理的XML很大,因此使用DOM当然效率低下。然而,我遇到的另一个问题是xml文件有40,000个信息条目,其结构很复杂。这是它的一点摘录:

<metabolite>
  <version>3.5</version>
  <creation_date>2005-11-16 08:48:42 -0700</creation_date>
  <update_date>2013-02-08 17:07:44 -0700</update_date>
  <accession>HMDB00002</accession>
  <secondary_accessions>
  </secondary_accessions>
  <name>1,3-Diaminopropane</name>
  <description>1,3-Diaminopropane is a stable, flammable and highly hydroscopic fluid. It is a polyamine that is normally quite toxic if swallowed, inhaled or absorbed through the skin. It is a catabolic byproduct of spermidine. It is also a precursor in the enzymatic synthesis of beta-alanine. 1, 3-Diaminopropane is involved in the arginine/proline metabolic pathways and the beta-alanine metabolic pathway.</description>
  <synonyms>
    <synonym>1,3-Diamino-N-propane</synonym>
    <synonym>1,3-Propanediamine</synonym>
    <synonym>1,3-Propylenediamine</synonym>
    <synonym>1,3-Trimethylenediamine</synonym>
    <synonym>3-Aminopropylamine</synonym>
    <synonym>a,w-Propanediamine</synonym>
    <synonym>Propane-1,3-diamine</synonym>
    <synonym>Trimethylenediamine</synonym>
  </synonyms>
  <chemical_formula>C3H10N2</chemical_formula>

所以这是40个条目中的一个,它包含更多元素等。我需要能够对我的程序做的是允许用户从40,000条目中选择他想要的信息,然后以excel表格的形式返回信息。因此,如果我只想说出所有40,000个条目的版本号和名称,它就会将这些值返回到excel中。目前我已经制作了一个循环使用StAX的程序,并通过打印到控制台返回所有元素和值。我将如何创建一个数据结构,例如树或其他东西,然后允许我做我想做的事情(即遍历该数据并仅返回我寻求的数据) 。

到目前为止,这是我在循环浏览文档并返回信息以便输入40,000个条目时所做的:

public class xmlRead {

    private static XMLStreamReader reader;

    public xmlRead(){

        try{

            InputStream file = new FileInputStream("/Users/Kevlar/Dropbox/PhD/Java/HMDB/testOutput.xml");
            XMLInputFactory inputFactory = XMLInputFactory.newInstance();

            reader = inputFactory.createXMLStreamReader(file);

            assert(reader.getEventType() == XMLEvent.START_DOCUMENT);   

        }   catch (XMLStreamException e){
            System.err.println("XMLStreamException : " + e.getMessage());

        }   catch (FactoryConfigurationError e){
            System.err.println("FactoryConfigurationError : " + e.getMessage());

        }   catch (FileNotFoundException e){
            System.err.println("FileNotFoundException : " + e.getMessage());

        }
    }

    public void metaboliteInfo() throws XMLStreamException{

        while(reader.hasNext()){

        int event = reader.getEventType();

        if(event == XMLStreamConstants.START_ELEMENT && reader.getLocalName() == "metabolite"){

            System.out.println("New " + reader.getLocalName());     
            mainElements(reader);
        }

        else if(event == XMLStreamConstants.END_DOCUMENT){
            System.out.println("end of document");
            break;

        }

        else{

        reader.next();

        }

        }

        reader.close();
    }


    public void mainElements(XMLStreamReader reader) throws XMLStreamException{

            int level = 1;

            do{

                int event = reader.next();

                if(event == XMLStreamConstants.START_ELEMENT){

                    System.out.println("Element :" + reader.getLocalName());
                    level++;

                    if(level == 2){
                        subElements(reader);
                        level--;
                    }
                }

                else if(event == XMLStreamConstants.CHARACTERS && !reader.isWhiteSpace()){
                    System.out.println(reader.getText());
                }

                else if(event == XMLStreamConstants.END_ELEMENT){
                    level--;
                }

            }while(level > 0);

        reader.close();

    }

    private void subElements(XMLStreamReader reader) throws XMLStreamException {

        int level = 1;

        do{

            int event = reader.next();

            if(event == XMLStreamConstants.START_ELEMENT){

                System.out.println("Sub element :" + reader.getLocalName());
                level++;

                if(level == 2){
                    subElements(reader);
                    level--;
                }
            }

            else if(event == XMLStreamConstants.CHARACTERS && !reader.isWhiteSpace()){
                System.out.println(reader.getText());
            }

            else if(event == XMLStreamConstants.END_ELEMENT){
                level--;
            }

        }while(level > 0);

    reader.close();

}

    public void findElements(XMLStreamReader reader, String element) throws XMLStreamException{

            int level = 1;

            do{

                int event = reader.next();

                if(event == XMLStreamConstants.START_ELEMENT){

                    if(reader.getLocalName() == element){
                        System.out.println(reader.getLocalName());
                    }
                    level++;

                    if(level == 2){
                        subElements(reader);
                        level--;
                    }
                }

                else if(event == XMLStreamConstants.CHARACTERS && !reader.isWhiteSpace()){
                    System.out.println(reader.getText());
                }

                else if(event == XMLStreamConstants.END_ELEMENT){
                    level--;
                }

            }while(level > 0);

        reader.close();

    }


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

        xmlRead test = new xmlRead();
        test.metaboliteInfo();

    }

}

我也应该在这里注意到,我实际上并不是程序员。我只是为了研究目的而处理这些XML文件,但没有其他人为我做这些,所以我对java的了解有限,我害怕(即用外行术语解释事情会很棒)。

2 个答案:

答案 0 :(得分:4)

查找JAXB。这是一个将XML转换为Java代码的框架,反之亦然。如果您使用JXB为您自动生成Java类,则不必担心手动滚动自己的数据结构。

您需要从XML模式开始,该模式定义了XML文件的外观。如果您还没有,则可以使用XMLSpy等工具从XML文件创建XML架构定义(XSD)文件。  JAXB提供了一个名为xjc的工具。这可以用于从XML模式自动生成Java类。在XML具有重复标记的地方,这些java类包含可以迭代的集合。

答案 1 :(得分:0)

XQuery解决方案。使用此exrpression,您可以过滤输入xml文档:

declare function local:rewrite($node as node()) as node()?
{
    typeswitch ($node)
    case element() return
        if (matches(local-name($node), "(version|name|synonym)")) then
            element {node-name($node)}
            {
                $node/@*,
                for $child in $node/node() return local:rewrite($child)
            }
        else
            ()
    default return
        $node
};

for $m in //metabolite
return <metabolite>{for $c in $m/node() return local:rewrite($c)}</metabolite>

(version|name|synonym)替换为与您需要提供的xml节点名称匹配的regexp。 评估XQuery表达式的Java 7代码:

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import javax.xml.transform.sax.SAXSource;
import javax.xml.transform.stream.StreamResult;
import net.sf.saxon.Configuration;
import net.sf.saxon.om.DocumentInfo;
import net.sf.saxon.query.DynamicQueryContext;
import net.sf.saxon.query.StaticQueryContext;
import net.sf.saxon.query.XQueryExpression;
import org.xml.sax.InputSource;
// inside a method
Configuration config = new Configuration();
StaticQueryContext sqc = config.newStaticQueryContext();
DynamicQueryContext dqc = new DynamicQueryContext(config);
String xq = "XQUERY_EXPRESSION";
try (InputStream xmlFileInput = new FileInputStream("data.xml");
        OutputStream xmlFileOutput = new FileOutputStream("data-filtered.xml")) {
    XQueryExpression expression = sqc.compileQuery(xq);
    SAXSource source = new SAXSource(new InputSource(xmlFileInput));
    DocumentInfo di = config.buildDocument(source);
    dqc.setContextItem(di);
    expression.run(dqc, new StreamResult(xmlFileOutput), null);
} catch (Exception e) {
    System.err.println(e.getMessage());
}

Saxon(例如saxon9he.jar)库必须存在于类路径中才能编译和运行此代码。