我有一个看起来像的XMl文件:
<?xml version="1.0" encoding="UTF-8"?>
<game >
<moves>
<turn>2</turn>
<piece nr="1" />
<turn>4</turn>
<piece nr="1" />
</moves>
</game>
我正在编写一个Java程序,它将XML文件作为输入,然后用SAX和SAX过滤器解析它并计算:
然后我想使用SAX过滤器来生成输出XML文件,该输出XML文件与输入XML文件相同,但有一个额外的元素,如:
<s:statistics>
<s:turn-total>6</s:turn-total>
<s:piece-count>2</s:piece-count>
</s:statistics>
前缀s
是对namespace的引用。
到目前为止,我的计划是:
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);
}
}
}
接下来我该怎么做?
答案 0 :(得分:4)
您的XMLFilter
应委托给根据萨克斯事件序列化文档的其他ContentHandler
。
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(...));
您的回调应委托给super
实施,该实施将事件转发给序列化ContentHandler
。
public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException {
super.startElement(namespaceURI, localName, qName, atts);
...
}
在endElement
回调中,您可以检查自己是否处于最终结束标记并添加其他萨克斯事件。
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");
}
...
}
答案 1 :(得分:0)
如果我错了,请纠正我,但我认为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();
}
使用此类来解析xml-Files,您只需要这样的类:
@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;
}
}
使用Move作为另一个类的实例,该类具有您需要的字段,并且还具有XmlRootElement的注释。
我希望这会有所帮助。
答案 2 :(得分:0)
使用@Jorn Horstmann(http://stackoverflow.com/users/139595/jorn-horstmann)上面的答案,您可以轻松添加缺少的元素。但是要将结果写入XML文件,您应该使用TransformerHandler。
只需创建一个非常基本的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();
然后(在其他函数中)添加: 例如对于startElement:
hd.startElement(uri,localName,name,attributes);
最后,您可以将所有这些内容写入endDocument方法中的文件。