使用 SAX 和 Java 生成 XML

发布于 2024-10-15 18:56:58 字数 1539 浏览 6 评论 0原文

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

懒猫 2024-10-22 18:56:58

SAX 解析用于读取文档,而不是写入文档。

您可以使用 XMLStreamWriter 编写 XML:

OutputStream outputStream = new FileOutputStream(new File("doc.xml"));

XMLStreamWriter out = XMLOutputFactory.newInstance().createXMLStreamWriter(
                new OutputStreamWriter(outputStream, "utf-8"));

out.writeStartDocument();
out.writeStartElement("doc");

out.writeStartElement("title");
out.writeCharacters("Document Title");
out.writeEndElement();

out.writeEndElement();
out.writeEndDocument();

out.close();

SAX parsing is for reading documents, not writing them.

You can write XML with the XMLStreamWriter:

OutputStream outputStream = new FileOutputStream(new File("doc.xml"));

XMLStreamWriter out = XMLOutputFactory.newInstance().createXMLStreamWriter(
                new OutputStreamWriter(outputStream, "utf-8"));

out.writeStartDocument();
out.writeStartElement("doc");

out.writeStartElement("title");
out.writeCharacters("Document Title");
out.writeEndElement();

out.writeEndElement();
out.writeEndDocument();

out.close();
晚雾 2024-10-22 18:56:58

有一种非常有用的技术可以通过 SAX 框架(不是 SAX 解析器,而是 SAX 框架)直接从 POJO 生成 XML。该技术可用于生成 XML 文档

从任意数据结构生成 XML
http://download.oracle.com/javaee/1.4/tutorial/doc /JAXPXSLT5.html

本质上,您向 POJO 添加方法或为 POJO 编写实用程序类,将它们转换为 SAX 事件发射器(像 SAX 解析器在解析 XML 文档时通常会发出事件一样)。现在,您的“SAX 事件生成器”看起来就像 SAX 解析器的输出端,并且可以为 SAX 解析器提供任何内容处理程序,例如漂亮地打印 XML 的内容处理程序。但它也可以提供给 DOM 解析器来生成 DOM 树,或者提供给 XSLT 引擎来生成 HTML 或执行真正的 XSL 转换,而无需首先从 POJO 生成中间 XML 文档。

例如,Person 类可能有一个 emitXML() 方法,其中包含以下几行:

handler.startElement(nsu, PERSON_TAG, PERSON_TAG, NO_ATTRIBUTES);

handler.startElement(nsu, FIRSTNAME_TAG, FIRSTNAME_TAG, atts);
handler.characters(this.firstName.toCharArray(), 
        0,
        this.firstName.length());
handler.endElement(nsu, FIRSTNAME_TAG, FIRSTNAME_TAG);

... emit more instance variables

... emit child object like: homeAddress.emitXML(handler, ...);

handler.endElement(nsu, PERSON_TAG, PERSON_TAG);

更新:

其他一些参考:


对评论的一些回应:

确实如此,但是上面描述的 XMLStreamWriter 接口更加用户友好。 – 迈克尔·凯 3 小时前

是的,但我想我不清楚。我可以轻松遍历层次结构并使用 XMLStreamWriter 将 XML 文档直接输出到流。 但是,这些文章展示了一种强大的技术来遍历层次结构并生成 SAX 事件,而不是直接输出 XML 文档。现在我可以插入不同的内容处理程序来执行不同的操作或生成不同版本的 XML。我们还可以将对象层次结构提供给任何接受 SAX 解析器的工具,例如 XSLT 引擎。它实际上只是利用了 SAX 框架建立的访问者模式:我们将遍历层次结构与输出 XML 分开。如果输出 XML 的部分(即内容处理程序)的目的是写入 XML 流,那么它们当然应该使用 XMLStreamWriter。

例如,在我们的程序中,我们通过网络套接字在分布式组件之间发送 XML 消息,并且我们还使用 XSLT 来生成 HTML 页面。以前,我们遍历层次结构来生成 XML 文档(字符串),然后将该 XML 文档写入网络套接字或将该文档提供给 XSLT 引擎(本质上只是再次解析它)。使用此技术后,我们基本上可以将对象层次结构(使用此 SAX 适配器)直接提供给 XSLT 引擎,而无需中间 XML 字符串。能够使用一个内容处理程序为网络流生成紧凑的 XML 表示,并使用不同的内容处理程序生成打印精美的 XML 文档以写入日志文件,这也很方便。

此外,使用 SAX 解析器 API 来编写 XML 是对 API 的滥用,恕我直言。 – 深褐色 49 分钟前

也许吧,但我认为这取决于您的需求。如果OP的要求只是写出一个特定的XML文档,那么这绝对是大材小用了。然而,我认为值得一提的是,如果 OP 在他的项目中以其他方式使用 XML,而他没有提到。提出替代想法并没有什么坏处。

称其为“滥用”可能有点过分,但我同意您有权发表自己的意见。它记录在 Oracle 教程中,因此不被视为 Sun/Oracle 工程师的滥用。它在我们的项目中非常成功,帮助我们满足我们的要求,并且没有重大缺点,因此我将把这种方法保留在我的工具箱中,以备将来使用。

There's a very useful technique for generating XML directly from POJOs via the SAX framework (not a SAX parser, but the SAX framework). This technique could be used to generate an XML document.

Generating XML from an Arbitrary Data Structure
http://download.oracle.com/javaee/1.4/tutorial/doc/JAXPXSLT5.html

Essentially, you add methods to your POJO or write utility class for your POJOs that turn them into SAX event emitters (emitting events like a SAX parser normally would when parsing an XML document). Now your "SAX event generator" looks like the output side of a SAX parser and can be given any content handler that a SAX parser would take, such as one that pretyy prints XML. But it could also be feed to a DOM parser to generate a DOM tree or feed to an XSLT engine to generate HTML or do a true XSL translation without having to first generate an intermediate XML document from the POJOs.

For example, a Person class might have an emitXML() method that include these lines:

handler.startElement(nsu, PERSON_TAG, PERSON_TAG, NO_ATTRIBUTES);

handler.startElement(nsu, FIRSTNAME_TAG, FIRSTNAME_TAG, atts);
handler.characters(this.firstName.toCharArray(), 
        0,
        this.firstName.length());
handler.endElement(nsu, FIRSTNAME_TAG, FIRSTNAME_TAG);

... emit more instance variables

... emit child object like: homeAddress.emitXML(handler, ...);

handler.endElement(nsu, PERSON_TAG, PERSON_TAG);

Update:

A couple of other references:


A couple of responses to comments:

This is true, but the XMLStreamWriter interface described above is much more user-friendly. – Michael Kay 3 hours ago

Yes, but I guess I wasn't clear. I could easy traverse the hierarchy and use XMLStreamWriter to directly output an XML document to a stream. However, the articles show a powerful technique to traverse the hierarchy and generate SAX events, instead of outputting an XML document directly. Now I can plug-in different content handlers that do different things or generate different versions of the XML. We could also feed our object hierarchy to any tool that accepted a SAX parser, like an XSLT engine. Its really just taking advantage of the visitor pattern established by the SAX framework: we separate traversing the hierarchy from output the XML. The parts that output the XML, the content handlers, should certainly use an XMLStreamWriter if their purpose is to write an XML stream.

For example, on our program, we sent XML messages over network sockets between distributed components and we also used XSLT to generate our HTML pages. Previously, we traversed our hierarchy to generate a XML document (a string) and then either wrote that XML document to a network socket or fed that document to the XSLT engine (which essentially just parsed it again). After using this technique, we could essentially feed our object hierarchy (using this SAX adapter) directly to the XSLT engine without needing the intermediate XML string. It was also convenient to be able to use one content handler to generate a compact XML representation for the network stream and use a different one to generate a pretty-printed XML document for writing to a log file.

Besides, using SAX parser API to write XML is a misuse of the API, IMHO. – Puce 49 mins ago

Perhaps, but I think it depends on your needs. If OP's requirement is just to write out an a specific XML document, then this is definitely overkill. However, I thought it worth mentioning if the OP uses XML in other ways on his project that he didn't mention. There's no harm in pitching an alternative idea.

Calling it misuse may be a bit strong, but I agree you're entitled to your opinion. Its documented in an Oracle tutorial, so its not considered abuse by the Sun/Oracle engineers. It was highly successful on our project to help us meet our requirements with no significant downsides, so I'll be keeping this approach in my toolbox for when its useful in the future.

枫以 2024-10-22 18:56:58

下面回答了“使用 SAX 解析器和 Java 编写 XML 的一个很好的教程”问题的一部分,

我不确定您是否已经经历过这个。但我真的很喜欢Java 的真正大索引

浏览以下内容: http://download.oracle.com/javase/tutorial/jaxp /index.html

最终,这个: http:// download.oracle.com/javase/tutorial/jaxp/sax/index.html

Below answers "a good tutorial for writing XML using the SAX parser and Java" part of question

I am not sure if you have gone through this. But I really like Java's Really Big Index of Everything.

Go through this: http://download.oracle.com/javase/tutorial/jaxp/index.html

And eventually, this: http://download.oracle.com/javase/tutorial/jaxp/sax/index.html

够钟 2024-10-22 18:56:58

请参考我的个人博文:Java 中的 XML 生成 - 具体来说,SAX 方法。它引用了一些与此相关的其他文章,提供了一个具体示例,并将 SAX 与其他用于从 Java 生成 XML 的流行 API 进行了比较。

(意识到这是一个较旧的问题,但认为有必要为可能有相同问题的其他人添加此问题。)

Please refer to my personal blog post: XML Generation In Java - specifically, The SAX method. It references a few other articles concerning this, provides a concrete example, and compares SAX with the other popular APIs for generating XML from Java.

(Realized this is an older question, but felt it necessary to add this for anyone else that may have the same question.)

以歌曲疗慰 2024-10-22 18:56:58

还可以考虑使用 JAXB 来写入/读取 XML。

Also consider JAXB to write/ read XML.

无边思念无边月 2024-10-22 18:56:58

您还可以通过以下方式桥接到 trax:

public abstract class PipedSAXSource extends SAXSource {
  protected PipedSAXSource() {
    setXMLReader(new CallWriteDuringSax());
  }

  protected abstract void writeTo(ContentHandler sink)
      throws IOException, SAXException;

  private class CallWriteDuringSax extends XMLFilterImpl {
    @Override
    public void parse(InputSource ignored) throws IOException, SAXException {
      writeTo(getContentHandler());
    }

    @Override
    public void setFeature(String name, boolean value) {}
  }
}

像这样使用:

  public static void main(String[] args) throws Exception {
    Source in = new PipedSAXSource() {
      @Override
      protected void writeTo(ContentHandler sink) throws SAXException {
        sink.startDocument();

        sink.startElement("", "root", "root", new AttributesImpl());
        sink.endElement("", "root", "root");

        sink.endDocument();
      }
    };

    Transformer identity = TransformerFactory.newInstance().newTransformer();
    identity.transform(in, new StreamResult(System.out));
  }

You can also bridge to trax with this:

public abstract class PipedSAXSource extends SAXSource {
  protected PipedSAXSource() {
    setXMLReader(new CallWriteDuringSax());
  }

  protected abstract void writeTo(ContentHandler sink)
      throws IOException, SAXException;

  private class CallWriteDuringSax extends XMLFilterImpl {
    @Override
    public void parse(InputSource ignored) throws IOException, SAXException {
      writeTo(getContentHandler());
    }

    @Override
    public void setFeature(String name, boolean value) {}
  }
}

Use like so:

  public static void main(String[] args) throws Exception {
    Source in = new PipedSAXSource() {
      @Override
      protected void writeTo(ContentHandler sink) throws SAXException {
        sink.startDocument();

        sink.startElement("", "root", "root", new AttributesImpl());
        sink.endElement("", "root", "root");

        sink.endDocument();
      }
    };

    Transformer identity = TransformerFactory.newInstance().newTransformer();
    identity.transform(in, new StreamResult(System.out));
  }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文