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>

XMLファイルを入力として受け取り、それをSAXおよびSAXフィルタで解析して計算するJavaプログラムを作成しています:

  • ターン要素のコンテンツの合計 (ここでは = 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

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、イベントを serializing に転送する実装に委譲する必要があります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");
    }
    ...
}
于 2012-05-15T11:11:10.813 に答える
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 ファイルを解析すると、次のようなクラスのみが必要になります。

@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 に答える
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 に答える