java 使用 SAX 过滤器将新元素插入 XML 文件
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/10598035/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Insert new element to an XML file using SAX Filter
提问by Kenan Hadad
I have an XMl file that looks like:
我有一个 XML 文件,看起来像:
<?xml version="1.0" encoding="UTF-8"?>
<game >
<moves>
<turn>2</turn>
<piece nr="1" />
<turn>4</turn>
<piece nr="1" />
</moves>
</game>
I am writing a Java program that takes the XML file as input then parses it with SAX and SAX filter and computes:
我正在编写一个 Java 程序,它将 XML 文件作为输入,然后用 SAX 和 SAX 过滤器解析它并计算:
- the sum of the content of turn element (here=6)
- the number of piece elements (here=2)
- 转元素内容的总和(此处=6)
- 片元素的数量(这里= 2)
Then I want to use a SAX filter in order to generate an output XML file that are the same as the input one but with an additional element like:
然后我想使用 SAX 过滤器来生成一个与输入相同的输出 XML 文件,但有一个额外的元素,如:
<s:statistics>
<s:turn-total>6</s:turn-total>
<s:piece-count>2</s:piece-count>
</s:statistics>
The prefix s
is a reference to a namespace.
前缀s
是对命名空间的引用。
My program so far is:
到目前为止,我的程序是:
public class test{
public static void main(String[] args) throws Exception {
if (args.length != 2) {
System.err.println("error ");
System.exit(1);
}
String xmlInput = args[0];
String filteredXML = args[1];
test test1 = new test();
test1.sax(xmlInput, filteredXML);
}
private void sax(String gameXML, String filteredGameXML)throws Exception{
FileInputStream fis = new FileInputStream( gameXML);
InputSource is = new InputSource(fis);
XMLReader xr = XMLReaderFactory.createXMLReader();
XMLFilter xf = new MyFilter();
xf.setParent(xr);
xr = xf;
xr.parse(is);
xr.setFeature("http://xml.org/sax/features/namespaces", true);
DefaultHandler handler = new DefaultHandler();
xr.setContentHandler(handler);
}
private class MyFilter extends XMLFilterImpl{
StringBuffer buffer;
int temp=0;
int sum=0;
String ff;
int numof=0;
private MyFilter() {}
@Override
public void startDocument() throws SAXException {
System.out.println( "START DOCUMENT" );
numof=0;
}
public void startElement(String namespaceURI, String localName, String name, Attributes attributes) throws SAXException{
if(localName.equals("turn")){
buffer=new StringBuffer();
}
if("piece".equals(name)){
numof++;
}
}
public void characters(char[] ch, int start, int length) throws SAXException {
String s=new String(ch, start, length);
if(buffer!=null){
buffer.append(s);
}
}
public void endElement(String uri, String localName, String name)throws SAXException {
if(buffer!=null ){
ff=buffer.toString();
temp=Integer.valueOf(ff);
sum=sum+temp;
}
buffer=null;
}
public void endDocument() throws SAXException {
System.out.println( "END DOCUMENT" );
System.out.println("sum of turn: "+ sum);
System.out.println("sum of piece: "+ numof);
}
}
}
What should I do next?
我接下来该怎么做?
回答by J?rn Horstmann
Your XMLFilter
should delegate to another ContentHandler
that serializes the document based on the sax events.
您XMLFilter
应该委托给另一个ContentHandler
根据 sax 事件序列化文档的人。
SAXTransformerFactory factory = (SAXTransformerFactory)TransformerFactory.newInstance();
TransformerHandler serializer = factory.newTransformerHandler();
Result result = new StreamResult(...);
serializer.setResult(result);
XMLFilterImpl filter = new MyFilter();
filter.setContentHandler(serializer);
XMLReader xmlreader = XMLReaderFactory.createXMLReader();
xmlreader.setFeature("http://xml.org/sax/features/namespaces", true);
xmlreader.setFeature("http://xml.org/sax/features/namespace-prefixes", true);
xmlreader.setContentHandler(filter);
xmlreader.parse(new InputSource(...));
Your callback should delegate to the super
implementation, which forwards the events to the serializing ContentHandler
.
您的回调应委托给super
实现,该实现将事件转发到序列化ContentHandler
.
public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException {
super.startElement(namespaceURI, localName, qName, atts);
...
}
In your endElement
callback you can check if your are at the final closing tag and add additional sax events.
在您的endElement
回调中,您可以检查您是否在最后的结束标记处并添加其他 sax 事件。
public void endElement(String namespaceURI, String localName, String qName) throws SAXException {
super.endElement(namespaceURI, localName, qName);
if ("game".equals(localName)) {
super.startElement("", "statistics", "statistics", new AttributesImpl());
char[] chars = String.valueOf(num).toCharArray();
super.characters(chars, 0, chars.length);
super.endElement("", "statistics", "statistics");
}
...
}
回答by Johannes
Using @Jorn Horstmann's (http://stackoverflow.com/users/139595/jorn-horstmann) answer from above you can easily add the missing elements. But to write the results to an XML file you should use the TransformerHandler.
使用上面的@Jorn Horstmann (http://stackoverflow.com/users/139595/jorn-horstmann) 的答案,您可以轻松添加缺少的元素。但是要将结果写入 XML 文件,您应该使用 TransformerHandler。
Just create a very basic ContentHandler and use it instead of the DefaultHandler. In the ContentHandler you can implement all the basic functions (startDocument, startElement etc.) and add every element to a new Transformer. e.g. In your startDocument function:
只需创建一个非常基本的 ContentHandler 并使用它代替 DefaultHandler。在 ContentHandler 中,您可以实现所有基本功能(startDocument、startElement 等)并将每个元素添加到新的 Transformer。例如在你的 startDocument 函数中:
Transformer t = hd.getTransformer();
t.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
t.setOutputProperty(OutputKeys.METHOD, "xml");
t.setOutputProperty(OutputKeys.INDENT, "yes");
hd.startDocument();
And then (in each other function) add this: e.g. for startElement:
然后(在每个其他函数中)添加这个:例如对于 startElement:
hd.startElement(uri,localName,name,attributes);
Finally you can write all this to a file in the endDocument method.
最后,您可以在 endDocument 方法中将所有这些写入文件。
回答by jobnz
Correct me if i'm wrong but i think XMLReader and XMLFilter are not really supposed to change a document. I can provide a different approach which with you can change the content of your document too:
如果我错了,请纠正我,但我认为 XMLReader 和 XMLFilter 并不真正应该更改文档。我可以提供一种不同的方法,您也可以更改文档的内容:
public class ExtXMLConfig {
private JAXBContext context;
private Marshaller m;
private Unmarshaller um;
private Schema schema = null;
/**
* Creates an ExtXMLConfig-object, which uses rootClass as object to parse
* and save XML-files.
*
* @param rootClass
* the class use create/parse xml-files from
* @throws JAXBException
*/
public ExtXMLConfig(Class<?> rootClass) throws JAXBException {
context = JAXBContext.newInstance(rootClass);
init();
}
/**
* Creates an ExtXMLConfig, which uses a classPath like javax.xml.bin to use
* all classes in that path to parse and write xml-files
*
* @param classPath
* the class path containing all needed java-objects
* @throws JAXBException
*/
public ExtXMLConfig(String classPath) throws JAXBException {
context = JAXBContext.newInstance(classPath);
init();
}
/**
* Parses a xml-file into a JavaObject.
*
* @param file
* path to the xml-file
* @return a java-Object
*/
public Object load(String file) {
return load(new File(file));
}
/**
* Parses a xml-file into a JavaObject.
*
* @param xml
* File-object representing the xml-file
* @return a java-Object
*/
public Object load(File xml) {
um.setSchema(schema);
if (xml.exists() && xml.isFile()) {
try {
return um.unmarshal(xml);
} catch (JAXBException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} else {
System.out.println("Failed to open file: " + xml.getAbsolutePath());
}
return null;
}
/**
* Saves a object into a xml-file.
*
* @param xml
* the object to save
* @param file
* path to the file to save to
*/
public void save(Object xml, String file) {
save(xml, new File(file));
}
/**
* Saves a object into a xml-file.
*
* @param xml
* the object to save
* @param file
* File-object representing the file to save to
*/
public void save(Object xml, File file) {
if (xml != null) {
m.setSchema(schema);
if (!file.isDirectory()) {
try {
if (!file.exists()) {
file.createNewFile();
}
m.marshal(xml, file);
} catch (JAXBException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
/**
* Returns a formatted string representation of a xml-file given as a
* java-Object.
*
* @param xml
* the java-object to parse the xml from.
* @return a formatted string representation of the given object
*/
public String toString(Object xml) {
StringWriter out = new StringWriter();
try {
m.setSchema(schema);
m.marshal(xml, out);
return out.toString();
} catch (JAXBException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
private void init() throws JAXBException {
m = context.createMarshaller();
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
m.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
um = context.createUnmarshaller();
}
Using this class to parse your xml-Files you would only need a Class like this:
使用这个类来解析你的 xml 文件,你只需要一个像这样的类:
@XmlRootElement // used to parse this class as xml-Root
public class Game {
private Move moves;
public Game() {};
public void setMove(Move moves) {
this.moves = moves;
}
public Moves getMoves() {
return this.moves;
}
}
with Move being an instance of another class which has the fields you need and also has a annotation for XmlRootElement.
Move 是另一个类的实例,该类具有您需要的字段,并且还有 XmlRootElement 的注释。
I hope this helps.
我希望这有帮助。