【问题标题】:analyzing inputstream xml format java分析inputstream xml格式java
【发布时间】:2018-10-15 14:58:57
【问题描述】:

我有一个 InputStream 包含如下 xml 格式:-

InputStream is = asStream("<TransactionList>\n" +
            "    <Transaction type=\"C\" amount=\"1000\"narration=\"salary\" />\n" +
            "    <Transaction type=\"X\" amount=\"400\" narration=\"rent\"/>\n" +
            "    <Transaction type=\"D\" amount=\"750\" narration=\"other\"/>\n" +
            "</TransactionList>");
 xmlTransactionProcessor.importTransactions(is);

我正在尝试对此进行分析并将值存储到 Transaction 对象(用户定义)的数组列表中,但我仍然无法这样做。

我尝试了很多解决方案,但仍然没有任何好处。

我阅读了有关读取 xml 文件的信息,但仍然无法处理这样的 InputStream。

有人可以帮忙吗?这是我最后一次尝试,但它仍然在某个地方失败。

    // TODO Auto-generated method stub
    BufferedReader inputReader = new BufferedReader(new InputStreamReader(is));
    StringBuilder sb = new StringBuilder();
    String inline = "";
    try {
        while ((inline = inputReader.readLine()) != null) {
          sb.append(inline);
        }
    } catch (Exception e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

    SAXBuilder builder = new SAXBuilder();

    try {
        org.jdom2.Document document = (org.jdom2.Document) builder.build(new ByteArrayInputStream(sb.toString().getBytes()));
    } catch (Exception e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

【问题讨论】:

  • 另一个不错的选择是jaxb

标签: java xml inputstream


【解决方案1】:

您不必使用 SAX 解析器自己解析 XML。有几个库允许XML Binding:将 XML 文档序列化和反序列化为自定义 POJO 类(或这些类的集合)。

JDK 中甚至还有一个用于 XML 绑定的标准。它被称为JAXB。您可以使用注释将 XML 元素名称映射到自定义 POJO 的属性。

这是我个人最喜欢的图书馆的一个例子:Jackson。它主要用于处理 JSON 格式的文本,但有 an extension 以支持 XML(和 JAXB)。

import java.util.*;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.dataformat.xml.*;

public class XMLTest
{
    public static void main(String[] args)
    {
        String input = 
            "<TransactionList>\n" +
            "    <Transaction type=\"C\" amount=\"1000\" narration=\"salary\" />\n" +
            "    <Transaction type=\"X\" amount=\"400\" narration=\"rent\"/>\n" +
            "    <Transaction type=\"D\" amount=\"750\" narration=\"other\"/>\n" +
            "</TransactionList>";
        try {
            XmlMapper xmlMapper = new XmlMapper();
            xmlMapper.setDefaultUseWrapper(false);
            // this is how we tell Jackson the target type of the deserialization 
            JavaType transactionListType = xmlMapper.getTypeFactory().constructCollectionType(List.class, Transaction.class);
            List<Transaction> transactionList = xmlMapper.readValue(input, transactionListType );
            System.out.println(transactionList);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static class Transaction
    {
        public String type;
        public int amount;
        public String narration;

        @Override
        public String toString() {
            return String.format("{ type:%s, amount:%d, narration:%s }", type, amount, narration);   
        }

    }
}

【讨论】:

  • 稍后我会尝试这个解决方案,现在它与另一个解决方案一起工作正常,但尝试多种解决方案是个好主意
  • 你是什么意思“另一种解决方案”,手动萨克斯解析?这是迄今为止更好、更安全、开发速度更快、可读性更强的解决方案。
  • 另一个答案中的解决方案,刚刚使用它然后注意到这个解决方案,是的,它似乎更快,我试试吧
【解决方案2】:

正如 Sharon Ben Asher 所解释的,您可以使用 JAXBJackson with XML data formatter 来使用带注释的数据映射。这会更容易。

如果您想使用 SAXParser 修复现有代码,请按以下步骤操作。

您必须像下面的代码那样迭代文档对象。

public static void main(String[] args) {
    InputStream is = new ByteArrayInputStream(("<TransactionList>\n" +
            "    <Transaction type=\"C\" amount=\"1000\" narration=\"salary\" />\n" +
            "    <Transaction type=\"X\" amount=\"400\" narration=\"rent\"/>\n" +
            "    <Transaction type=\"D\" amount=\"750\" narration=\"other\"/>\n" +
            "</TransactionList>").getBytes(StandardCharsets.UTF_8));
    ArrayList transactions = importTransactions(is);
}

importTransaction 方法中,使用getRootElement 获取根级别的Transactions 元素。然后使用 getChildren 和 for-each 循环遍历每个 Transaction 子元素。

public static ArrayList<Transaction> importTransactions(InputStream is){
        ArrayList<Transaction> transactions = new ArrayList<>();
        BufferedReader inputReader = new BufferedReader(new InputStreamReader(is));
        StringBuilder sb = new StringBuilder();
        String inline = "";
        try {
            while ((inline = inputReader.readLine()) != null) {
                sb.append(inline);
            }
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        SAXBuilder builder = new SAXBuilder();

        try {
            org.jdom2.Document document = builder.build(new ByteArrayInputStream(sb.toString().getBytes()));
            Element transactionsElement = document.getRootElement();

            List<Element> transactionList = transactionsElement.getChildren();

            for (Element transaction:transactionList) {
                Transaction t = new Transaction();
                t.setType(transaction.getAttribute("type").getValue());
                t.setAmount(transaction.getAttribute("amount").getValue());
                transactions.add(t);

            }

        } catch (Exception e) {
            // Log the error....
            e.printStackTrace();
        }
        return transactions;
    }

【讨论】:

  • 非常感谢您的回复,效果很好,您拯救了我的一天..我真的很感激
  • 对于这个解决方案,"transaction.getAttribute("amount")"的值为"[Attribute:amount="1000"]",如何只提取amount(1000)的值?
  • 知道了,只需使用 getValue 之类的 transaction.getAttribute("amount").getValue();
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-05-22
  • 1970-01-01
  • 2021-12-25
  • 2010-10-29
  • 2017-01-28
  • 1970-01-01
相关资源
最近更新 更多