【问题标题】:XML into data structure in java using sax, stax or DOM使用 sax、stax 或 DOM 将 XML 转换为 java 中的数据结构
【发布时间】:2015-01-13 15:11:27
【问题描述】:

所以过去两周我一直在研究我的这个项目,但我没有取得任何进展。我的问题不是一开始就解析 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 的了解是有限的(即用外行术语解释事情会很棒)。

【问题讨论】:

  • 您找到解决方案了吗?
  • 我做了,我只是从网上复制了一个 TreeNode 类,它似乎正在工作,我无法得到其他人建议的工作

标签: java xml dom xml-parsing stax


【解决方案1】:

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

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

【讨论】:

  • 但是,如果 xml 文件有 40,000 个条目,您能否编写一个模式,这些条目将包含许多相同的元素,但在某些情况下可能不同,或者某些区域的元素比其他的?就像我在 XML 文件中的条目一样,它们不遵循一种特定格式,因为它们都包含相同数量的元素和元素类型
  • 是的,例如,如果一个代谢物没有同义词、一个同义词或 100 个同义词,xjc 会为您生成一个类,其中 Metabolite 类包含同义词的集合。这个同义词集合可以是空的,可以包含一个项目,也可以包含 100 个项目,具体取决于您当前的 Metabolite 记录。
  • 如果您可以创建 XSD,您会发现它尽可能地具有限制性,同时仍然对所有 40000 条记录有效。您的自动生成的类将足够灵活,可以对所有记录进行建模。
  • 刚刚想到。如果它从模式中自动创建类,那是不是意味着我基本上对每种不同的元素类型都有一个 setter 和 getter 方法?
  • 是的,你会的,但是使用自动生成的类的一种方法是使用 JAXB 的解组;这将为您填充类的集合。如果需要,您可以自己填充类并编组回 XML。
【解决方案2】:

XQuery 解决方案。使用此表达式,您可以过滤输入 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 节点名称匹配的正则表达式。 评估 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)库必须存在于类路径中才能编译和运行此代码。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-29
    相关资源
    最近更新 更多