的问题,你”再有就是当你创建StAXSource
,你START_ELEMENT事件已经被消耗。所以XMLEventReader
可能是在一些空白文本节点事件,还是其他什么东西不能是一个XML文档源。您可以使用peek()
方法,无需消耗它来查看下一个事件。尽管如此,确保首先有hasNext()
的事件发生。
我不是100%确定你想完成什么,所以这里有些事情可以根据情况做。
编辑:我刚看了一些这让事情变得更清晰一点上你的问题的意见。下面的内容仍然可以帮助你通过一些调整来达到预期的效果。还要注意的是Java的XSLT处理器允许扩展函数和扩展元素,它可以从一个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>
我绑定的eg
前缀一些虚拟命名空间,因为它是从你的示例中缺少固定的格式不正确的RST元素。
以下程序将对您的输入运行XSLT转换并将其写入输出文件。
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);
}
}
}
下面是一个示例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>
以上样式将默认复制一切,但是当它到达一个<gml:featureMember>
元素将内容包装成一个新的<gml:member>
元素。只是XSLT可以做什么的一个非常简单的例子。
输出将是:
<?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>
由于两个输入和输出文件流,你不需要在内存中的整个DOM。 Java中的XSLT非常快速高效,所以这可能就足够了。
也许你真的想把每一个元素出现在它自己的输出文件中,并对它进行一些修改。以下是使用StAX将<gml:featureMember>
元素拆分为单独文档的代码示例。然后,您可以遍历所创建的文件,然后根据需要进行转换(XSLT再次是个不错的选择)。显然,错误处理需要更强大一点。这仅仅是为了演示。
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;
}
}
}
}
}
你有没有考虑与流XSLT 3.0解决它由撒克逊9 EE从saxonica.com支持?如果您编辑问题并向我们展示您希望在'featureMember'元素上实现哪些更改,以及您是要生成包含所有更改元素的单个结果还是每个更改元素的新文档,那么我可以告诉您如何执行该操作以声明的方式使用XSLT 3.0。 –
我对XSLT 3.0一无所知,所以我没有考虑它。我无法真正说出我想在'featureMember'元素上改变什么 - 它取决于用户(这就是为什么我需要DOM)。我必须通过它的localID找到特定的'featureMember',并改变它的一些元素。我有一张桌子,上面有我想做的更改(它们并不总是相同的)。我想用所有更改的元素生成单个结果。 – sophiess
是的,我很感兴趣。我已经做了它(它工作,但有点太慢 - 每个文件1小时)。如果真的更有效率,我可以使用一些帮助。 – sophiess