XMLの特定の要素だけをパースしたい場合がある。他のメソッドやクラスにパース処理を委譲してしまいたいのが主な理由だ。
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<array name="preloaded_drawables">
<item>@drawable/indicator_code_lock_drag_direction_green_up</item>
<item>@drawable/indicator_code_lock_drag_direction_red_up</item>
</array>
<array name="preloaded_color_state_lists">
<item>@color/hint_foreground_dark</item>
<item>@color/hint_foreground_light</item>
</array>
<integer-array name="maps_starting_lat_lng">
<item>36149777</item>
<item>-95993398</item>
</integer-array>
<integer-array name="maps_starting_zoom">
<item>3</item>
</integer-array>
</resources>こんなXMLがあったとして、
このような場合、サブツリーだけを処理するXMLパーサがあると便利であり.NET C#等では標準のプルパーサに同様の実装がありとても重宝する。残念ながらJavaのプルパーサにはそのような機能は無いが、以前にJava6用のものを作ったことがある。
[Java]無いなら作ろう - XMLStreamSubReader
同様にAndroid用にも作ったが、以前用意したものはXmlResourcePullParserがベースであり広範囲には使いづらいので、改めてXMLPullParserインタフェースをベースに作り直した。
-
- XmlPullParserDelegate.java
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
public class XmlPullParserDelegate implements XmlPullParser {
protected final XmlPullParser delegate;
public XmlPullParserDelegate(XmlPullParser delegate) {
this.delegate = delegate;
}
/* (non-Javadoc)
* @see org.xmlpull.v1.XmlPullParser#defineEntityReplacementText(java.lang.String, java.lang.String)
*/
@Override
public void defineEntityReplacementText(String entityName,
String replacementText) throws XmlPullParserException {
this.delegate.defineEntityReplacementText(entityName, replacementText);
}
/* (non-Javadoc)
* @see org.xmlpull.v1.XmlPullParser#getAttributeCount()
*/
@Override
public int getAttributeCount() {
return this.delegate.getAttributeCount();
}
/* (non-Javadoc)
* @see org.xmlpull.v1.XmlPullParser#getAttributeName(int)
*/
@Override
public String getAttributeName(int index) {
return this.delegate.getAttributeName(index);
}
/* (non-Javadoc)
* @see org.xmlpull.v1.XmlPullParser#getAttributeNamespace(int)
*/
@Override
public String getAttributeNamespace(int index) {
return this.delegate.getAttributeNamespace(index);
}
/* (non-Javadoc)
* @see org.xmlpull.v1.XmlPullParser#getAttributePrefix(int)
*/
@Override
public String getAttributePrefix(int index) {
return this.delegate.getAttributePrefix(index);
}
/* (non-Javadoc)
* @see org.xmlpull.v1.XmlPullParser#getAttributeType(int)
*/
@Override
public String getAttributeType(int index) {
return this.delegate.getAttributeType(index);
}
/* (non-Javadoc)
* @see org.xmlpull.v1.XmlPullParser#getAttributeValue(int)
*/
@Override
public String getAttributeValue(int index) {
return this.delegate.getAttributeValue(index);
}
/* (non-Javadoc)
* @see org.xmlpull.v1.XmlPullParser#getAttributeValue(java.lang.String, java.lang.String)
*/
@Override
public String getAttributeValue(String namespace, String name) {
return this.delegate.getAttributeValue(namespace, name);
}
/* (non-Javadoc)
* @see org.xmlpull.v1.XmlPullParser#getColumnNumber()
*/
@Override
public int getColumnNumber() {
return this.delegate.getColumnNumber();
}
/* (non-Javadoc)
* @see org.xmlpull.v1.XmlPullParser#getDepth()
*/
@Override
public int getDepth() {
return this.delegate.getDepth();
}
/* (non-Javadoc)
* @see org.xmlpull.v1.XmlPullParser#getEventType()
*/
@Override
public int getEventType() throws XmlPullParserException {
return this.delegate.getEventType();
}
/* (non-Javadoc)
* @see org.xmlpull.v1.XmlPullParser#getFeature(java.lang.String)
*/
@Override
public boolean getFeature(String name) {
return this.delegate.getFeature(name);
}
/* (non-Javadoc)
* @see org.xmlpull.v1.XmlPullParser#getInputEncoding()
*/
@Override
public String getInputEncoding() {
return this.delegate.getInputEncoding();
}
/* (non-Javadoc)
* @see org.xmlpull.v1.XmlPullParser#getLineNumber()
*/
@Override
public int getLineNumber() {
return this.delegate.getLineNumber();
}
/* (non-Javadoc)
* @see org.xmlpull.v1.XmlPullParser#getName()
*/
@Override
public String getName() {
return this.delegate.getName();
}
/* (non-Javadoc)
* @see org.xmlpull.v1.XmlPullParser#getNamespace()
*/
@Override
public String getNamespace() {
return this.delegate.getNamespace();
}
/* (non-Javadoc)
* @see org.xmlpull.v1.XmlPullParser#getNamespace(java.lang.String)
*/
@Override
public String getNamespace(String prefix) {
return this.delegate.getNamespace(prefix);
}
/* (non-Javadoc)
* @see org.xmlpull.v1.XmlPullParser#getNamespaceCount(int)
*/
@Override
public int getNamespaceCount(int depth) throws XmlPullParserException {
return this.delegate.getNamespaceCount(depth);
}
/* (non-Javadoc)
* @see org.xmlpull.v1.XmlPullParser#getNamespacePrefix(int)
*/
@Override
public String getNamespacePrefix(int pos) throws XmlPullParserException {
return this.delegate.getNamespacePrefix(pos);
}
/* (non-Javadoc)
* @see org.xmlpull.v1.XmlPullParser#getNamespaceUri(int)
*/
@Override
public String getNamespaceUri(int pos) throws XmlPullParserException {
return this.delegate.getNamespaceUri(pos);
}
/* (non-Javadoc)
* @see org.xmlpull.v1.XmlPullParser#getPositionDescription()
*/
@Override
public String getPositionDescription() {
return this.delegate.getPositionDescription();
}
/* (non-Javadoc)
* @see org.xmlpull.v1.XmlPullParser#getPrefix()
*/
@Override
public String getPrefix() {
return this.delegate.getPrefix();
}
/* (non-Javadoc)
* @see org.xmlpull.v1.XmlPullParser#getProperty(java.lang.String)
*/
@Override
public Object getProperty(String name) {
return this.delegate.getProperty(name);
}
/* (non-Javadoc)
* @see org.xmlpull.v1.XmlPullParser#getText()
*/
@Override
public String getText() {
return this.delegate.getText();
}
/* (non-Javadoc)
* @see org.xmlpull.v1.XmlPullParser#getTextCharacters(int[])
*/
@Override
public char[] getTextCharacters(int[] holderForStartAndLength) {
return this.delegate.getTextCharacters(holderForStartAndLength);
}
/* (non-Javadoc)
* @see org.xmlpull.v1.XmlPullParser#isAttributeDefault(int)
*/
@Override
public boolean isAttributeDefault(int index) {
return this.delegate.isAttributeDefault(index);
}
/* (non-Javadoc)
* @see org.xmlpull.v1.XmlPullParser#isEmptyElementTag()
*/
@Override
public boolean isEmptyElementTag() throws XmlPullParserException {
return this.delegate.isEmptyElementTag();
}
/* (non-Javadoc)
* @see org.xmlpull.v1.XmlPullParser#isWhitespace()
*/
@Override
public boolean isWhitespace() throws XmlPullParserException {
return this.delegate.isWhitespace();
}
/* (non-Javadoc)
* @see org.xmlpull.v1.XmlPullParser#next()
*/
@Override
public int next() throws XmlPullParserException, IOException {
return this.delegate.next();
}
/* (non-Javadoc)
* @see org.xmlpull.v1.XmlPullParser#nextTag()
*/
@Override
public int nextTag() throws XmlPullParserException, IOException {
return this.delegate.nextTag();
}
/* (non-Javadoc)
* @see org.xmlpull.v1.XmlPullParser#nextText()
*/
@Override
public String nextText() throws XmlPullParserException, IOException {
return this.delegate.nextText();
}
/* (non-Javadoc)
* @see org.xmlpull.v1.XmlPullParser#nextToken()
*/
@Override
public int nextToken() throws XmlPullParserException, IOException {
return this.delegate.nextToken();
}
/* (non-Javadoc)
* @see org.xmlpull.v1.XmlPullParser#require(int, java.lang.String, java.lang.String)
*/
@Override
public void require(int type, String namespace, String name)
throws XmlPullParserException, IOException {
this.delegate.require(type, namespace, name);
}
/* (non-Javadoc)
* @see org.xmlpull.v1.XmlPullParser#setFeature(java.lang.String, boolean)
*/
@Override
public void setFeature(String name, boolean state)
throws XmlPullParserException {
this.delegate.setFeature(name, state);
}
/* (non-Javadoc)
* @see org.xmlpull.v1.XmlPullParser#setInput(java.io.Reader)
*/
@Override
public void setInput(Reader in) throws XmlPullParserException {
this.delegate.setInput(in);
}
/* (non-Javadoc)
* @see org.xmlpull.v1.XmlPullParser#setInput(java.io.InputStream, java.lang.String)
*/
@Override
public void setInput(InputStream inputStream, String inputEncoding)
throws XmlPullParserException {
this.delegate.setInput(inputStream, inputEncoding);
}
/* (non-Javadoc)
* @see org.xmlpull.v1.XmlPullParser#setProperty(java.lang.String, java.lang.Object)
*/
@Override
public void setProperty(String name, Object value)
throws XmlPullParserException {
this.delegate.setProperty(name, value);
}
}
XmlPullParserDelegateはパーサの処理を委譲するだけだ。
-
- XmlPullSubtreeParser.java
import java.io.IOException;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
public class XmlPullSubtreeParser extends XmlPullParserDelegate {
protected String rootNode;
protected int rootDepth;
protected int lastEvent;
protected int lastDepth;
public XmlPullSubtreeParser(XmlPullParser delegateParser) {
super(delegateParser);
this.rootDepth = delegateParser.getDepth();
this.lastDepth = this.rootDepth;
this.rootNode = delegateParser.getName();
}
public String getRootName() {
return this.rootNode;
}
/* (non-Javadoc)
* @see org.jaffa.util.xml.XmlResourceParserDelegate#next()
*/
@Override
public int next() throws XmlPullParserException, IOException {
if ( this.hasNext() ) {
this.lastEvent = super.next();
this.lastDepth = this.getDepth();
return this.lastEvent;
} else {
return 0;
}
}
public boolean hasNext() throws XmlPullParserException {
if ( this.rootDepth > this.lastDepth ) {
return false;
}
if ( this.lastEvent == XmlPullParser.END_TAG ) {
if ( this.getName().equals(this.rootNode)) {
return false;
}
if ( this.rootDepth >= this.lastDepth ) {
return false;
}
}
if ( this.delegate instanceof XmlPullSubtreeParser ) {
return ((XmlPullSubtreeParser)this.delegate).hasNext();
} else {
return (this.lastEvent != XmlPullParser.END_DOCUMENT);
}
}
}XmlPullSubtreeParserはコンストラクタの引数で与えられたXmlPullParserの要素と深度を基準にしてその直下の要素だけをパースする。何をしているかは見れば解るだろう。
※コードは一応テストを通っているがその動作は保証しない。