0

SAX パーサーを使用して、インターネットから変更できないドキュメントを解析しています。ドキュメントが次のようにフォーマットされたとき、それはうまく機能していました:

<outtertag>
  <innertag>data</innertag>
  <innerag>moreData</innertag>
</outtertag>

ただし、XML が外側のタグなしでフォーマットされている場合に行う特定の呼び出しがあるため、基本的に次のようなデータのリストのみを取得します。

  <innertag>data</innertag>
  <innerag>moreData</innertag>

これはばかげているように思えますが、XML のフォーマット方法を選択することはできず、今のところ変更することはできません。問題は、SAX パーサーが endDocument イベントを最初の終了タグにヒットするとすぐにヒットするように見えることです。

私は、InputStream を文字列に変換し、その周りにタグを投げてから、それを InputStream に変換するというかなりハックなソリューションを持っています。実際にはそのようにうまく解析されます。しかし、きっともっと良い方法があります。また、他のパーサー全体を作成したくありません。開始タグと終了タグがないことを除けば、ほとんどのタグは同じです。

念のため、コードを投稿しますが、これはかなり標準的な SAX パーサーです。オリジナルは、実際には約 30 個のタグを解析しています。

        SAXParserFactory factory = SAXParserFactory.newInstance();
        SAXParser saxParser = factory.newSAXParser();
        XMLReader xmlReader = saxParser.getXMLReader();

        MyHandler handler = new MyHandler();
        xmlReader.setContentHandler(handler);

        InputSource inputSource = new InputSource(url.openStream());
        xmlReader.parse(inputSource);
    }

    catch (SAXException e) { e.printStackTrace(); } 
    catch (ParserConfigurationException e) { e.printStackTrace(); }
    catch(Exception e) { e.printStackTrace(); }
}

private class MyHandler extends DefaultHandler {
    private StringBuilder content;

    public MyHandler() {
        content = new StringBuilder();
    }
    public void startElement(String uri, String localName, String qName, 
            Attributes atts) throws SAXException {
        content = new StringBuilder();
        if(localName.equalsIgnoreCase("innertag")) {
            //Doing stuff
        }

    }
    public void endElement(String uri, String localName, String qName) 
            throws SAXException {

        //Doing stuff
    }
    public void characters(char[] ch, int start, int length) 
            throws SAXException {
        content.append(ch, start, length);
    }
    public void endDocument() throws SAXException {
               //When parsing the second type of document, hits this event almost immediately after parsing first tag



    }
}

そして、それが重要な場合は、これが私が使用しているハックコードですが、間違っているように感じますが、動作します:

BufferedReader reader = new BufferedReader(new InputStreamReader(url.openStream()));
        StringBuilder sb = new StringBuilder("<tag>");
        String line = null;

        while ((line = reader.readLine()) != null) {
            sb.append(line);
        }           
        sb.append("</tag>");
        String xml =sb.toString();

        InputStream is = new ByteArrayInputStream(xml.getBytes());
        InputSource source = new InputSource(is);
        xmlReader.parse(source);
4

2 に答える 2

1

あなたが今していることは、あなたが得られるのと同じくらい良いと思います. 特にドキュメントが大きい場合は、ストリーム -> 文字列 -> ストリームの変換を改善することを検討してください。文字列の代わりにストリームを連結できるGuava のByteStreams.join()のようなものを使用できます。次のようなもの:

import com.google.common.io.*;
import java.io.*;

public class ConcatenateStreams {
    public static void main(String[] args) throws Exception {
        InputStream malformedXmlContent = externalXmlStream();
        InputSupplier<InputStream> joined = ByteStreams.join(
                inputSupplier("<root>"),
                inputSupplier(malformedXmlContent),
                inputSupplier("</root>"));
        ByteStreams.copy(joined, System.out);
    }

    private static InputStream externalXmlStream() {
        return new ByteArrayInputStream("<foo>5</foo><bar>10</bar>".getBytes());
    }

    private static InputSupplier<InputStream> inputSupplier(final String text) {
        return inputSupplier(new ByteArrayInputStream(text.getBytes()));
    }

    private static InputSupplier<InputStream> inputSupplier(final InputStream inputStream) {
        return new InputSupplier<InputStream>() {
            @Override
            public InputStream getInput() throws IOException {
                return inputStream;
            }
        };
    }
}

出力:

<root><foo>5</foo><bar>10</bar></root>
于 2013-02-19T02:27:45.493 に答える
0

取得した XML は整形式のドキュメントではありませんが、整形式の外部解析済みエンティティです。つまり、エンティティ参照によって整形式のドキュメントから参照できます。したがって、次のようなスケルトン ドキュメントを作成します。

<!DOCTYPE doc [
<!ENTITY e SYSTEM "data.xml">
]>
<doc>&e;</doc>

ここで、data.xml は XML であり、元のドキュメントの代わりにこのドキュメントを XML パーサーに渡します。数十行の Java コードを書くよりも優れています。

于 2013-02-19T08:39:08.857 に答える