implement namespace features as per xmlpull #18

This commit is contained in:
REAndroid 2023-05-03 17:09:45 +02:00
parent db3a18b039
commit b8d410803d
2 changed files with 75 additions and 22 deletions

View File

@ -36,11 +36,12 @@ public class ResXmlPullParser implements XmlResourceParser {
private DocumentLoadedListener documentLoadedListener; private DocumentLoadedListener documentLoadedListener;
private boolean processNamespaces; private boolean processNamespaces;
private boolean reportNamespaceAttrs; private boolean reportNamespaceAttrs;
private boolean mIsTagStared;
public ResXmlPullParser(Decoder decoder){ public ResXmlPullParser(Decoder decoder){
this.mDecoder = decoder; this.mDecoder = decoder;
this.processNamespaces = true; this.processNamespaces = false;
this.reportNamespaceAttrs = true; this.reportNamespaceAttrs = false;
} }
public ResXmlPullParser(){ public ResXmlPullParser(){
this(null); this(null);
@ -93,6 +94,7 @@ public class ResXmlPullParser implements XmlResourceParser {
public void closeDocument(){ public void closeDocument(){
mEventList.clear(); mEventList.clear();
mIsTagStared = false;
destroyDocument(); destroyDocument();
} }
private void destroyDocument(){ private void destroyDocument(){
@ -118,14 +120,14 @@ public class ResXmlPullParser implements XmlResourceParser {
return 0; return 0;
} }
int count = element.getAttributeCount(); int count = element.getAttributeCount();
if(reportNamespaceAttrs){ if(isCountNamespacesAsAttribute()){
count += element.getNamespaceCount(); count += element.getNamespaceCount();
} }
return count; return count;
} }
@Override @Override
public String getAttributeName(int index) { public String getAttributeName(int index) {
if(reportNamespaceAttrs){ if(isCountNamespacesAsAttribute()){
int nsCount = getNamespaceCountInternal(); int nsCount = getNamespaceCountInternal();
if(index < nsCount){ if(index < nsCount){
return getNamespaceAttributeName(index); return getNamespaceAttributeName(index);
@ -135,7 +137,7 @@ public class ResXmlPullParser implements XmlResourceParser {
} }
@Override @Override
public String getAttributeValue(int index) { public String getAttributeValue(int index) {
if(reportNamespaceAttrs){ if(isCountNamespacesAsAttribute()){
int nsCount = getNamespaceCountInternal(); int nsCount = getNamespaceCountInternal();
if(index < nsCount){ if(index < nsCount){
return getNamespaceAttributeValue(index); return getNamespaceAttributeValue(index);
@ -345,13 +347,20 @@ public class ResXmlPullParser implements XmlResourceParser {
@Override @Override
public void setFeature(String name, boolean state) throws XmlPullParserException { public void setFeature(String name, boolean state) throws XmlPullParserException {
boolean changed;
if(FEATURE_PROCESS_NAMESPACES.equals(name)) { if(FEATURE_PROCESS_NAMESPACES.equals(name)) {
changed = processNamespaces != state;
processNamespaces = state; processNamespaces = state;
}else if(FEATURE_REPORT_NAMESPACE_ATTRIBUTES.equals(name)) { }else if(FEATURE_REPORT_NAMESPACE_ATTRIBUTES.equals(name)) {
changed = reportNamespaceAttrs != state;
reportNamespaceAttrs = state; reportNamespaceAttrs = state;
}else { }else {
throw new XmlPullParserException("Unsupported feature: " + name); throw new XmlPullParserException("Unsupported feature: " + name);
} }
if(changed && mIsTagStared){
throw new XmlPullParserException("Feature changed during parsing: "
+ name + ", state=" + state);
}
} }
@Override @Override
@ -392,7 +401,7 @@ public class ResXmlPullParser implements XmlResourceParser {
} }
@Override @Override
public int getNamespaceCount(int depth) throws XmlPullParserException { public int getNamespaceCount(int depth) throws XmlPullParserException {
if(reportNamespaceAttrs){ if(isCountNamespacesAsAttribute()){
return 0; return 0;
} }
ResXmlElement element = getCurrentElement(); ResXmlElement element = getCurrentElement();
@ -593,7 +602,7 @@ public class ResXmlPullParser implements XmlResourceParser {
return null; return null;
} }
private int getRealAttributeIndex(int index){ private int getRealAttributeIndex(int index){
if(reportNamespaceAttrs){ if(isCountNamespacesAsAttribute()){
index = index - getNamespaceCountInternal(); index = index - getNamespaceCountInternal();
} }
return index; return index;
@ -605,6 +614,9 @@ public class ResXmlPullParser implements XmlResourceParser {
} }
return 0; return 0;
} }
private boolean isCountNamespacesAsAttribute(){
return processNamespaces & reportNamespaceAttrs;
}
private String getNamespaceAttributeName(int index){ private String getNamespaceAttributeName(int index){
ResXmlStartNamespace namespace = getCurrentElement() ResXmlStartNamespace namespace = getCurrentElement()
.getNamespace(index); .getNamespace(index);
@ -628,9 +640,9 @@ public class ResXmlPullParser implements XmlResourceParser {
mEventList.next(); mEventList.next();
int type = mEventList.getType(); int type = mEventList.getType();
if(type == START_TAG){ if(type == START_TAG){
onStartTag(); mIsTagStared = true;
} }
return mEventList.getType(); return type;
} }
@Override @Override
public int nextToken() throws XmlPullParserException, IOException { public int nextToken() throws XmlPullParserException, IOException {
@ -711,9 +723,6 @@ public class ResXmlPullParser implements XmlResourceParser {
processNamespaces = true; processNamespaces = true;
reportNamespaceAttrs = true; reportNamespaceAttrs = true;
} }
private void onStartTag(){
}
public static interface DocumentLoadedListener{ public static interface DocumentLoadedListener{
public ResXmlDocument onDocumentLoaded(ResXmlDocument resXmlDocument); public ResXmlDocument onDocumentLoaded(ResXmlDocument resXmlDocument);

View File

@ -20,17 +20,22 @@ import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer; import org.xmlpull.v1.XmlSerializer;
import java.io.Closeable;
import java.io.IOException; import java.io.IOException;
public class XmlParserToSerializer { public class XmlParserToSerializer {
private final XmlSerializer serializer; private final XmlSerializer serializer;
private final XmlResourceParser parser; private final XmlPullParser parser;
private boolean enableIndent; private boolean enableIndent;
boolean processNamespace;
boolean reportNamespaceAttrs;
public XmlParserToSerializer(XmlResourceParser parser, XmlSerializer serializer){ public XmlParserToSerializer(XmlPullParser parser, XmlSerializer serializer){
this.parser = parser; this.parser = parser;
this.serializer = serializer; this.serializer = serializer;
this.enableIndent = true; this.enableIndent = true;
setFeatureSafe(parser, XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
setFeatureSafe(parser, XmlPullParser.FEATURE_REPORT_NAMESPACE_ATTRIBUTES, true);
} }
public void setEnableIndent(boolean enableIndent) { public void setEnableIndent(boolean enableIndent) {
@ -38,15 +43,29 @@ public class XmlParserToSerializer {
} }
public void write() throws IOException, XmlPullParserException { public void write() throws IOException, XmlPullParserException {
XmlResourceParser parser = this.parser; XmlPullParser parser = this.parser;
this.processNamespace = getFeatureSafe(parser,
XmlPullParser.FEATURE_PROCESS_NAMESPACES, false);
this.reportNamespaceAttrs = getFeatureSafe(parser,
XmlPullParser.FEATURE_REPORT_NAMESPACE_ATTRIBUTES, false);
int event = parser.next(); int event = parser.next();
while (nextEvent(event)){ while (nextEvent(event)){
event = parser.next(); event = parser.next();
} }
close(); close();
} }
private void close(){ private void close() throws IOException {
parser.close(); XmlPullParser parser = this.parser;
if(parser instanceof Closeable){
((Closeable)parser).close();
}
XmlSerializer serializer = this.serializer;
if(serializer instanceof Closeable){
((Closeable)serializer).close();
}
} }
private boolean nextEvent(int event) throws IOException, XmlPullParserException { private boolean nextEvent(int event) throws IOException, XmlPullParserException {
boolean hasNext = true; boolean hasNext = true;
@ -78,12 +97,17 @@ public class XmlParserToSerializer {
serializer.startDocument("utf-8", null); serializer.startDocument("utf-8", null);
} }
private void onStartTag() throws IOException, XmlPullParserException { private void onStartTag() throws IOException, XmlPullParserException {
XmlResourceParser parser = this.parser; XmlPullParser parser = this.parser;
XmlSerializer serializer = this.serializer; XmlSerializer serializer = this.serializer;
boolean processNamespace = parser.getFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES);
boolean reportNamespaceAttrs = parser.getFeature(XmlPullParser.FEATURE_REPORT_NAMESPACE_ATTRIBUTES); boolean processNamespace = this.processNamespace;
serializer.setFeature(FEATURE_INDENT_OUTPUT, enableIndent); boolean countNamespaceAsAttribute = processNamespace && reportNamespaceAttrs;
if(!reportNamespaceAttrs){
if(enableIndent){
setFeatureSafe(serializer, FEATURE_INDENT_OUTPUT, true);
}
if(!countNamespaceAsAttribute){
int nsCount = parser.getNamespaceCount(parser.getDepth()); int nsCount = parser.getNamespaceCount(parser.getDepth());
for(int i=0; i<nsCount; i++){ for(int i=0; i<nsCount; i++){
String prefix = parser.getNamespacePrefix(i); String prefix = parser.getNamespacePrefix(i);
@ -115,5 +139,25 @@ public class XmlParserToSerializer {
serializer.endDocument(); serializer.endDocument();
} }
private static boolean getFeatureSafe(XmlPullParser parser, String name, boolean def){
try{
return parser.getFeature(name);
}catch (Throwable ignored){
return def;
}
}
private static void setFeatureSafe(XmlPullParser parser, String name, boolean state){
try{
parser.setFeature(name, state);
}catch (Throwable ignored){
}
}
private static void setFeatureSafe(XmlSerializer serializer, String name, boolean state){
try{
serializer.setFeature(name, state);
}catch (Throwable ignored){
}
}
private static final String FEATURE_INDENT_OUTPUT = "http://xmlpull.org/v1/doc/features.html#indent-output"; private static final String FEATURE_INDENT_OUTPUT = "http://xmlpull.org/v1/doc/features.html#indent-output";
} }