4

我有一个 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 过滤器对其进行解析并计算:

  • turn 元素内容的总和(这里=6)
  • 块元素的数量(这里=2)

然后我想使用 SAX 过滤器来生成一个输出 XML 文件,该文件与输入文件相同,但带有一个附加元素,例如:

<s:statistics>
    <s:turn-total>6</s:turn-total>
    <s:piece-count>2</s:piece-count>
</s:statistics>

前缀s是对命名空间的引用。

到目前为止,我的程序是:

 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);
                }
         }

    }

接下来我该怎么办?

4

3 回答 3

4

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(...));

您的回调应委托给super实现,后者将事件转发给序列化ContentHandler.

public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException {
    super.startElement(namespaceURI, localName, qName, atts);
    ...
}

在您的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");
    }
    ...
}
于 2012-05-15T11:11:10.813 回答
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 方法中将所有这些写入文件。

于 2012-05-18T21:14:16.923 回答
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 的注释。

我希望这有帮助。

于 2012-05-15T10:30:18.850 回答