如何在Java中使用StAX读取和修改XML片段?
我的目标是将对象(featureMember)读入DOM,更改它们并写回新的XML。XML太大,无法使用DOM本身。我想我需要的是StAX和TransformerFactory,但我不能让它工作 这就是我到目前为止所做的:如何在Java中使用StAX读取和修改XML片段?,java,xml,dom,stax,Java,Xml,Dom,Stax,我的目标是将对象(featureMember)读入DOM,更改它们并写回新的XML。XML太大,无法使用DOM本身。我想我需要的是StAX和TransformerFactory,但我不能让它工作 这就是我到目前为止所做的: private void change(File pathIn, File pathOut) { try { XMLInputFactory factory = XMLInputFactory.newInstance(); XMLOu
private void change(File pathIn, File pathOut) {
try {
XMLInputFactory factory = XMLInputFactory.newInstance();
XMLOutputFactory factoryOut = XMLOutputFactory.newInstance();
TransformerFactory tf = TransformerFactory.newInstance();
Transformer t = tf.newTransformer();
XMLEventReader in = factory.createXMLEventReader(new FileReader(pathIn));
XMLEventWriter out = factoryOut.createXMLEventWriter(new FileWriter(pathOut));
while (in.hasNext()) {
XMLEvent e = in.nextTag();
if (e.getEventType() == XMLStreamConstants.START_ELEMENT) {
if (((StartElement) e).getName().getLocalPart().equals("featureMember")) {
DOMResult result = new DOMResult();
t.transform(new StAXSource(in), result);
Node domNode = result.getNode();
System.out.println(domnode);
}
}
out.add(e);
}
in.close();
out.close();
} catch (FileNotFoundException e1) {
e1.printStackTrace();
} catch (IOException e1) {
e1.printStackTrace();
} catch (TransformerConfigurationException e1) {
e1.printStackTrace();
} catch (XMLStreamException e1) {
e1.printStackTrace();
} catch (TransformerException e1) {
e1.printStackTrace();
}
}
我得到异常(在t.transform()上):
我的xml的简化版本如下(它有名称空间):
克拉科夫
id1234
1002
热舒夫
id1235
我有一个对象(featureMember)的localId列表,我想更改这些对象,并对更改的RST或pole进行相应的编码(这取决于更改的用户):
本地(id1234)RST(1001)
本地(id1236)RST(1003)
…您遇到的问题是,当您创建
statxSource
时,您的START\u元素事件已被使用。因此,XMLEventReader
可能在某个空白文本节点事件中,或者在其他不能作为XML文档源的事件中。您可以使用peek()
方法查看下一个事件而不使用它。不过,请确保有一个事件是以hasNext()
开头的
我不能百分之百确定您希望完成什么,因此根据具体情况,您可以做一些事情
编辑:我刚刚读了一些关于你问题的评论,这些评论让事情变得更清楚了。下面的内容仍然可以帮助您通过一些调整来实现所需的结果。还要注意,JavaXSLT处理器允许扩展函数和扩展元素,它们可以从XSLT样式表调用Java代码。这是一种使用外部资源(如数据库查询)扩展基本XSLT功能的强大方法
如果希望将输入XML转换为一个输出XML,那么最好只使用XML样式表转换。在代码中,您创建了一个没有任何模板的转换器,因此它成为默认的“标识转换器”,只将输入复制到输出。假设您的输入XML如下所示:
<?xml version="1.0" encoding="UTF-8"?>
<gml:FeatureCollection xmlns:gml="http://www.opengis.net/gml/3.2" gml:id="featureCollection" xmlns:eg="acme.com">
<gml:featureMember>
<eg:RST/>
<eg:pole>Krakow</eg:pole>
<eg:localId>id1234</eg:localId>
</gml:featureMember>
<gml:featureMember>
<eg:RST>1002</eg:RST>
<eg:pole>Rzeszow</eg:pole>
<eg:localId>id1235</eg:localId>
</gml:featureMember>
</gml:FeatureCollection>
这里是一个示例stylesheet.xsl文件,为了方便起见,我刚刚将其转储到与输入XML和类相同的包中
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0" xmlns:gml="http://www.opengis.net/gml/3.2" xmlns:eg="acme.com">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*" />
</xsl:copy>
</xsl:template>
<xsl:template match="gml:featureMember">
<gml:member>
<xsl:apply-templates select="node()|@*" />
</gml:member>
</xsl:template>
</xsl:stylesheet>
您是否考虑过使用saxonica.com上Saxon 9 EE支持的流式XSLT 3.0解决这个问题?如果您编辑您的问题,并向我们展示您希望在
featureMember
元素上实现的更改,以及您是否希望为所有更改的元素生成一个结果,或者为每个更改的元素生成一个新文档,那么我可以向您展示如何以声明的方式使用XSLT 3.0实现这一点。我对XSLT 3.0一无所知,所以我没有考虑。我真的说不出我想要在featureMember
元素上更改什么-这取决于用户(这就是我在这里需要DOM的原因)。我必须通过它的localID找到特定的featureMember
,并更改它的一些元素。我有一个表,其中有我想要做的更改(它们并不总是相同的)。我想用所有更改的元素生成一个结果。是的,我很感兴趣。我已经设法做到了(它可以工作,但有点太慢了——每个文件1小时)。如果它真的更有效,我可以使用一些帮助。好的,我将提交一个代码示例,这是有帮助的,但我不确定它是否解决了我的问题。我必须更改每个featureMember-首先检查localId,然后更改其余属性。样式表可以这样做吗?StAX的问题是它只能继续前进。lokalId可以位于featureMember的末尾,因此当事件发生时,我无法更改以前的元素。@sophiess XSLT在这种情况下是否易于使用在某种程度上取决于您计划如何使用该ID。如果转换仅取决于ID和XML中包含的其他信息,那么XSLT就可以了。如果你必须利用外部资源,这将变得更加困难,可能不是最好的选择。看看样式表转换可以做些什么。如果你陷入困境,你可以在这里问一个与他们相关的问题,或者搜索类似的问题。
<?xml version="1.0" encoding="UTF-8"?>
<gml:FeatureCollection xmlns:gml="http://www.opengis.net/gml/3.2" gml:id="featureCollection" xmlns:eg="acme.com">
<gml:featureMember>
<eg:RST/>
<eg:pole>Krakow</eg:pole>
<eg:localId>id1234</eg:localId>
</gml:featureMember>
<gml:featureMember>
<eg:RST>1002</eg:RST>
<eg:pole>Rzeszow</eg:pole>
<eg:localId>id1235</eg:localId>
</gml:featureMember>
</gml:FeatureCollection>
package xsltplayground;
import java.io.File;
import java.net.URL;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
public class XSLTplayground {
public static void main(String[] args) throws Exception {
URL url = XSLTplayground.class.getResource("sample.xml");
File input = new File(url.toURI());
URL url2 = XSLTplayground.class.getResource("stylesheet.xsl");
File xslt = new File(url2.toURI());
URL url3 = XSLTplayground.class.getResource(".");
File output = new File(new File(url3.toURI()), "output.xml");
change(input, output, xslt);
}
private static void change(File pathIn, File pathOut, File xsltFile) {
try {
// Creating transformer with XSLT file
TransformerFactory tf = TransformerFactory.newInstance();
Source xsltSource = new StreamSource(xsltFile);
Transformer t = tf.newTransformer(xsltSource);
// Input source
Source input = new StreamSource(pathIn);
// Output target
Result output = new StreamResult(pathOut);
// Transforming
t.transform(input, output);
} catch (TransformerConfigurationException ex) {
Logger.getLogger(XSLTplayground.class.getName()).log(Level.SEVERE, null, ex);
} catch (TransformerException ex) {
Logger.getLogger(XSLTplayground.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0" xmlns:gml="http://www.opengis.net/gml/3.2" xmlns:eg="acme.com">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*" />
</xsl:copy>
</xsl:template>
<xsl:template match="gml:featureMember">
<gml:member>
<xsl:apply-templates select="node()|@*" />
</gml:member>
</xsl:template>
</xsl:stylesheet>
<?xml version="1.0" encoding="UTF-8"?>
<gml:FeatureCollection xmlns:gml="http://www.opengis.net/gml/3.2" xmlns:eg="acme.com" gml:id="featureCollection">
<gml:member>
<eg:RST/>
<eg:pole>Krakow</eg:pole>
<eg:localId>id1234</eg:localId>
</gml:member>
<gml:member>
<eg:RST>1002</eg:RST>
<eg:pole>Rzeszow</eg:pole>
<eg:localId>id1235</eg:localId>
</gml:member>
</gml:FeatureCollection>
package xsltplayground;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URL;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.xml.stream.XMLEventFactory;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLEventWriter;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.events.XMLEvent;
import javax.xml.transform.stream.StreamSource;
public class XSLTplayground {
public static void main(String[] args) throws Exception {
URL url = XSLTplayground.class.getResource("sample.xml");
File input = new File(url.toURI());
URL url2 = XSLTplayground.class.getResource("stylesheet.xsl");
File xslt = new File(url2.toURI());
URL url3 = XSLTplayground.class.getResource(".");
File output = new File(url3.toURI());
change(input, output, xslt);
}
private static void change(File pathIn, File directoryOut, File xsltFile) throws InterruptedException {
try {
// Creating a StAX event reader from the input
XMLInputFactory xmlIf = XMLInputFactory.newFactory();
XMLEventReader reader = xmlIf.createXMLEventReader(new StreamSource(pathIn));
// Create a StAX output factory
XMLOutputFactory xmlOf = XMLOutputFactory.newInstance();
int counter = 1;
// Keep going until no more events
while (reader.hasNext()) {
// Peek into the next event to find out what it is
XMLEvent next = reader.peek();
// If it's the start of a featureMember element, commence output
if (next.isStartElement()
&& next.asStartElement().getName().getLocalPart().equals("featureMember")) {
File output = new File(directoryOut, "output_" + counter + ".xml");
try (OutputStream ops = new FileOutputStream(output)) {
XMLEventWriter writer = xmlOf.createXMLEventWriter(ops);
copy(reader, writer);
writer.flush();
writer.close();
}
counter++;
} else {
// Not in a featureMember element: ignore
reader.next();
}
}
} catch (XMLStreamException ex) {
Logger.getLogger(XSLTplayground.class.getName()).log(Level.SEVERE, null, ex);
} catch (IOException ex) {
Logger.getLogger(XSLTplayground.class.getName()).log(Level.SEVERE, null, ex);
}
}
private static void copy(XMLEventReader reader, XMLEventWriter writer) throws XMLStreamException {
// Creating an XMLEventFactory
XMLEventFactory ef = XMLEventFactory.newFactory();
// Writing an XML document start
writer.add(ef.createStartDocument());
int depth = 0;
boolean stop = false;
while (!stop) {
XMLEvent next = reader.nextEvent();
writer.add(next);
if (next.isStartElement()) {
depth++;
} else if (next.isEndElement()) {
depth--;
if (depth == 0) {
writer.add(ef.createEndDocument());
stop = true;
}
}
}
}
}