implement xml pp namespace features #18

This commit is contained in:
REAndroid 2023-05-02 16:41:33 +02:00
parent e8fff620f7
commit 0ec2b3fe1c
6 changed files with 1224 additions and 1105 deletions

View File

@ -1,4 +1,4 @@
/* /*
* Copyright (C) 2022 github.com/REAndroid * Copyright (C) 2022 github.com/REAndroid
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");

View File

@ -123,12 +123,13 @@ public class ResXmlAttribute extends ValueItem implements AttributeValue, Compar
startNamespace.addAttributeReference(this); startNamespace.addAttributeReference(this);
} }
private void unLinkStartNameSpace(){ private void unLinkStartNameSpace(){
ResXmlElement xmlElement=getParentResXmlElement(); ResXmlElement xmlElement = getParentResXmlElement();
if(xmlElement==null){ if(xmlElement == null){
return; return;
} }
ResXmlStartNamespace startNamespace=xmlElement.getStartNamespaceByUriRef(getNamespaceReference()); ResXmlStartNamespace startNamespace =
if(startNamespace==null){ xmlElement.getStartNamespaceByUriRef(getNamespaceReference());
if(startNamespace == null){
return; return;
} }
startNamespace.removeAttributeReference(this); startNamespace.removeAttributeReference(this);

View File

@ -1,4 +1,4 @@
/* /*
* Copyright (C) 2022 github.com/REAndroid * Copyright (C) 2022 github.com/REAndroid
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -13,26 +13,26 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.reandroid.arsc.chunk.xml; package com.reandroid.arsc.chunk.xml;
import com.reandroid.arsc.chunk.ChunkType; import com.reandroid.arsc.chunk.ChunkType;
import com.reandroid.arsc.base.Block; import com.reandroid.arsc.base.Block;
import com.reandroid.arsc.container.BlockList; import com.reandroid.arsc.container.BlockList;
import com.reandroid.arsc.container.SingleBlockContainer; import com.reandroid.arsc.container.SingleBlockContainer;
import com.reandroid.arsc.header.HeaderBlock; import com.reandroid.arsc.header.HeaderBlock;
import com.reandroid.arsc.io.BlockReader; import com.reandroid.arsc.io.BlockReader;
import com.reandroid.arsc.pool.ResXmlStringPool; import com.reandroid.arsc.pool.ResXmlStringPool;
import com.reandroid.common.EntryStore; import com.reandroid.common.EntryStore;
import com.reandroid.json.JSONConvert; import com.reandroid.json.JSONConvert;
import com.reandroid.json.JSONArray; import com.reandroid.json.JSONArray;
import com.reandroid.json.JSONObject; import com.reandroid.json.JSONObject;
import com.reandroid.xml.*; import com.reandroid.xml.*;
import java.io.IOException; import java.io.IOException;
import java.util.*; import java.util.*;
public class ResXmlElement extends ResXmlNode implements JSONConvert<JSONObject>, public class ResXmlElement extends ResXmlNode implements JSONConvert<JSONObject>,
Comparator<ResXmlNode> { Comparator<ResXmlNode> {
private final BlockList<ResXmlStartNamespace> mStartNamespaceList; private final BlockList<ResXmlStartNamespace> mStartNamespaceList;
private final SingleBlockContainer<ResXmlStartElement> mStartElementContainer; private final SingleBlockContainer<ResXmlStartElement> mStartElementContainer;
@ -553,6 +553,12 @@
public List<ResXmlStartNamespace> getStartNamespaceList(){ public List<ResXmlStartNamespace> getStartNamespaceList(){
return mStartNamespaceList.getChildes(); return mStartNamespaceList.getChildes();
} }
public int getNamespaceCount(){
return mStartNamespaceList.size();
}
public ResXmlStartNamespace getNamespace(int index){
return mStartNamespaceList.get(index);
}
public void addStartNamespace(ResXmlStartNamespace item){ public void addStartNamespace(ResXmlStartNamespace item){
mStartNamespaceList.add(item); mStartNamespaceList.add(item);
} }
@ -562,6 +568,14 @@
public void addEndNamespace(ResXmlEndNamespace item){ public void addEndNamespace(ResXmlEndNamespace item){
mEndNamespaceList.add(item); mEndNamespaceList.add(item);
} }
void removeNamespace(ResXmlStartNamespace startNamespace){
if(startNamespace == null){
return;
}
startNamespace.onRemoved();
mStartNamespaceList.remove(startNamespace);
mEndNamespaceList.remove(startNamespace.getEnd());
}
ResXmlStartElement newStartElement(int lineNo){ ResXmlStartElement newStartElement(int lineNo){
ResXmlStartElement startElement=new ResXmlStartElement(); ResXmlStartElement startElement=new ResXmlStartElement();
@ -1021,4 +1035,4 @@
private static final String NAME_line = "line"; private static final String NAME_line = "line";
static final String NAME_attributes = "attributes"; static final String NAME_attributes = "attributes";
static final String NAME_childes = "childes"; static final String NAME_childes = "childes";
} }

View File

@ -1,4 +1,4 @@
/* /*
* Copyright (C) 2022 github.com/REAndroid * Copyright (C) 2022 github.com/REAndroid
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -34,9 +34,13 @@ public class ResXmlPullParser implements XmlResourceParser {
private ResXmlDocument mDocument; private ResXmlDocument mDocument;
private boolean mDocumentCreatedHere; private boolean mDocumentCreatedHere;
private DocumentLoadedListener documentLoadedListener; private DocumentLoadedListener documentLoadedListener;
private boolean processNamespaces;
private boolean reportNamespaceAttrs;
public ResXmlPullParser(Decoder decoder){ public ResXmlPullParser(Decoder decoder){
this.mDecoder = decoder; this.mDecoder = decoder;
this.processNamespaces = true;
this.reportNamespaceAttrs = true;
} }
public ResXmlPullParser(){ public ResXmlPullParser(){
this(null); this(null);
@ -54,6 +58,7 @@ public class ResXmlPullParser implements XmlResourceParser {
public synchronized void setResXmlDocument(ResXmlDocument xmlDocument){ public synchronized void setResXmlDocument(ResXmlDocument xmlDocument){
closeDocument(); closeDocument();
this.mDocument = xmlDocument; this.mDocument = xmlDocument;
initDefaultFeatures();
initializeDecoder(xmlDocument); initializeDecoder(xmlDocument);
xmlDocument.addEvents(mEventList); xmlDocument.addEvents(mEventList);
} }
@ -109,17 +114,33 @@ public class ResXmlPullParser implements XmlResourceParser {
@Override @Override
public int getAttributeCount() { public int getAttributeCount() {
ResXmlElement element = getCurrentElement(); ResXmlElement element = getCurrentElement();
if(element!=null){ if(element == null){
return element.getAttributeCount();
}
return 0; return 0;
} }
int count = element.getAttributeCount();
if(reportNamespaceAttrs){
count += element.getNamespaceCount();
}
return count;
}
@Override @Override
public String getAttributeName(int index) { public String getAttributeName(int index) {
if(reportNamespaceAttrs){
int nsCount = getNamespaceCountInternal();
if(index < nsCount){
return getNamespaceAttributeName(index);
}
}
return decodeAttributeName(getResXmlAttributeAt(index)); return decodeAttributeName(getResXmlAttributeAt(index));
} }
@Override @Override
public String getAttributeValue(int index) { public String getAttributeValue(int index) {
if(reportNamespaceAttrs){
int nsCount = getNamespaceCountInternal();
if(index < nsCount){
return getNamespaceAttributeValue(index);
}
}
return decodeAttributeValue(getResXmlAttributeAt(index)); return decodeAttributeValue(getResXmlAttributeAt(index));
} }
@Override @Override
@ -324,9 +345,22 @@ 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 {
if(FEATURE_PROCESS_NAMESPACES.equals(name)) {
processNamespaces = state;
}else if(FEATURE_REPORT_NAMESPACE_ATTRIBUTES.equals(name)) {
reportNamespaceAttrs = state;
}else {
throw new XmlPullParserException("Unsupported feature: " + name);
} }
}
@Override @Override
public boolean getFeature(String name) { public boolean getFeature(String name) {
if(FEATURE_PROCESS_NAMESPACES.equals(name)) {
return processNamespaces;
}else if(FEATURE_REPORT_NAMESPACE_ATTRIBUTES.equals(name)) {
return reportNamespaceAttrs;
}
return false; return false;
} }
@Override @Override
@ -358,12 +392,15 @@ public class ResXmlPullParser implements XmlResourceParser {
} }
@Override @Override
public int getNamespaceCount(int depth) throws XmlPullParserException { public int getNamespaceCount(int depth) throws XmlPullParserException {
if(reportNamespaceAttrs){
return 0;
}
ResXmlElement element = getCurrentElement(); ResXmlElement element = getCurrentElement();
while(element!=null && element.getDepth()>depth){ while(element!=null && element.getDepth()>depth){
element=element.getParentResXmlElement(); element=element.getParentResXmlElement();
} }
if(element!=null){ if(element!=null){
return element.getStartNamespaceList().size(); return element.getNamespaceCount();
} }
return 0; return 0;
} }
@ -371,7 +408,7 @@ public class ResXmlPullParser implements XmlResourceParser {
public String getNamespacePrefix(int pos) throws XmlPullParserException { public String getNamespacePrefix(int pos) throws XmlPullParserException {
ResXmlElement element = getCurrentElement(); ResXmlElement element = getCurrentElement();
if(element!=null){ if(element!=null){
return element.getStartNamespaceList().get(pos).getPrefix(); return element.getNamespace(pos).getPrefix();
} }
return null; return null;
} }
@ -379,7 +416,7 @@ public class ResXmlPullParser implements XmlResourceParser {
public String getNamespaceUri(int pos) throws XmlPullParserException { public String getNamespaceUri(int pos) throws XmlPullParserException {
ResXmlElement element = getCurrentElement(); ResXmlElement element = getCurrentElement();
if(element!=null){ if(element!=null){
return element.getStartNamespaceList().get(pos).getUri(); return element.getNamespace(pos).getUri();
} }
return null; return null;
} }
@ -466,10 +503,13 @@ public class ResXmlPullParser implements XmlResourceParser {
if(element!=null){ if(element!=null){
return element.countResXmlNodes() == 0 && element.getAttributeCount()==0; return element.countResXmlNodes() == 0 && element.getAttributeCount()==0;
} }
return false; return true;
} }
@Override @Override
public String getAttributeNamespace(int index) { public String getAttributeNamespace(int index) {
if(processNamespaces){
return null;
}
ResXmlAttribute attribute = getResXmlAttributeAt(index); ResXmlAttribute attribute = getResXmlAttributeAt(index);
if(attribute != null){ if(attribute != null){
return attribute.getUri(); return attribute.getUri();
@ -478,6 +518,9 @@ public class ResXmlPullParser implements XmlResourceParser {
} }
@Override @Override
public String getAttributePrefix(int index) { public String getAttributePrefix(int index) {
if(processNamespaces){
return null;
}
ResXmlAttribute attribute = getResXmlAttributeAt(index); ResXmlAttribute attribute = getResXmlAttributeAt(index);
if(attribute != null){ if(attribute != null){
return attribute.getNamePrefix(); return attribute.getNamePrefix();
@ -493,7 +536,7 @@ public class ResXmlPullParser implements XmlResourceParser {
return false; return false;
} }
private String decodeAttributeName(ResXmlAttribute attribute){ private String decodeAttributeName(ResXmlAttribute attribute){
if(attribute==null){ if(attribute == null){
return null; return null;
} }
String name; String name;
@ -502,6 +545,9 @@ public class ResXmlPullParser implements XmlResourceParser {
name = attribute.getName(); name = attribute.getName();
}else { }else {
name = mDecoder.decodeResourceName(attribute.getNameResourceID(), true); name = mDecoder.decodeResourceName(attribute.getNameResourceID(), true);
if(processNamespaces){
name = attribute.getNamePrefix() + ":" + name;
}
} }
return name; return name;
} }
@ -512,6 +558,7 @@ public class ResXmlPullParser implements XmlResourceParser {
return mDecoder.decodeAttributeValue(attribute); return mDecoder.decodeAttributeValue(attribute);
} }
public ResXmlAttribute getResXmlAttributeAt(int index){ public ResXmlAttribute getResXmlAttributeAt(int index){
index = getRealAttributeIndex(index);
ResXmlElement element = getCurrentElement(); ResXmlElement element = getCurrentElement();
if(element == null){ if(element == null){
return null; return null;
@ -545,6 +592,33 @@ public class ResXmlPullParser implements XmlResourceParser {
} }
return null; return null;
} }
private int getRealAttributeIndex(int index){
if(reportNamespaceAttrs){
index = index - getNamespaceCountInternal();
}
return index;
}
private int getNamespaceCountInternal(){
ResXmlElement element = getCurrentElement();
if(element != null){
return element.getNamespaceCount();
}
return 0;
}
private String getNamespaceAttributeName(int index){
ResXmlStartNamespace namespace = getCurrentElement()
.getNamespace(index);
String prefix = namespace.getPrefix();
if(processNamespaces){
prefix = "xmlns:" + prefix;
}
return prefix;
}
private String getNamespaceAttributeValue(int index){
ResXmlStartNamespace namespace = getCurrentElement()
.getNamespace(index);
return namespace.getUri();
}
@Override @Override
public int getEventType() throws XmlPullParserException { public int getEventType() throws XmlPullParserException {
return mEventList.getType(); return mEventList.getType();
@ -552,6 +626,10 @@ public class ResXmlPullParser implements XmlResourceParser {
@Override @Override
public int next() throws XmlPullParserException, IOException { public int next() throws XmlPullParserException, IOException {
mEventList.next(); mEventList.next();
int type = mEventList.getType();
if(type == START_TAG){
onStartTag();
}
return mEventList.getType(); return mEventList.getType();
} }
@Override @Override
@ -629,6 +707,13 @@ public class ResXmlPullParser implements XmlResourceParser {
this.mDocumentCreatedHere = true; this.mDocumentCreatedHere = true;
} }
} }
private void initDefaultFeatures(){
processNamespaces = 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

@ -1,4 +1,4 @@
/* /*
* Copyright (C) 2022 github.com/REAndroid * Copyright (C) 2022 github.com/REAndroid
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -13,17 +13,18 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.reandroid.arsc.chunk.xml; package com.reandroid.arsc.chunk.xml;
import com.reandroid.arsc.chunk.ChunkType; import com.reandroid.arsc.chunk.ChunkType;
import com.reandroid.xml.SchemaAttr; import com.reandroid.xml.SchemaAttr;
import com.reandroid.xml.XMLAttribute; import com.reandroid.xml.XMLAttribute;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; import java.util.Set;
public class ResXmlStartNamespace extends ResXmlNamespace { public class ResXmlStartNamespace extends ResXmlNamespace {
private final Set<ResXmlAttribute> mReferencedAttributes; private final Set<ResXmlAttribute> mReferencedAttributes;
public ResXmlStartNamespace() { public ResXmlStartNamespace() {
super(ChunkType.XML_START_NAMESPACE); super(ChunkType.XML_START_NAMESPACE);
this.mReferencedAttributes = new HashSet<>(); this.mReferencedAttributes = new HashSet<>();
@ -86,4 +87,4 @@
txt=txt.trim(); txt=txt.trim();
return txt.length()==0; return txt.length()==0;
} }
} }

View File

@ -1,4 +1,4 @@
/* /*
* Copyright (C) 2022 github.com/REAndroid * Copyright (C) 2022 github.com/REAndroid
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -16,6 +16,7 @@
package com.reandroid.xml; package com.reandroid.xml;
import android.content.res.XmlResourceParser; import android.content.res.XmlResourceParser;
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;
@ -24,10 +25,18 @@ import java.io.IOException;
public class XmlParserToSerializer { public class XmlParserToSerializer {
private final XmlSerializer serializer; private final XmlSerializer serializer;
private final XmlResourceParser parser; private final XmlResourceParser parser;
private boolean enableIndent;
public XmlParserToSerializer(XmlResourceParser parser, XmlSerializer serializer){ public XmlParserToSerializer(XmlResourceParser parser, XmlSerializer serializer){
this.parser = parser; this.parser = parser;
this.serializer = serializer; this.serializer = serializer;
this.enableIndent = true;
} }
public void setEnableIndent(boolean enableIndent) {
this.enableIndent = enableIndent;
}
public void write() throws IOException, XmlPullParserException { public void write() throws IOException, XmlPullParserException {
XmlResourceParser parser = this.parser; XmlResourceParser parser = this.parser;
int event = parser.next(); int event = parser.next();
@ -71,17 +80,24 @@ public class XmlParserToSerializer {
private void onStartTag() throws IOException, XmlPullParserException { private void onStartTag() throws IOException, XmlPullParserException {
XmlResourceParser parser = this.parser; XmlResourceParser parser = this.parser;
XmlSerializer serializer = this.serializer; XmlSerializer serializer = this.serializer;
serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true); boolean processNamespace = parser.getFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES);
boolean reportNamespaceAttrs = parser.getFeature(XmlPullParser.FEATURE_REPORT_NAMESPACE_ATTRIBUTES);
serializer.setFeature(FEATURE_INDENT_OUTPUT, enableIndent);
if(!reportNamespaceAttrs){
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);
String namespace = parser.getNamespaceUri(i); String namespace = parser.getNamespaceUri(i);
serializer.setPrefix(prefix, namespace); serializer.setPrefix(prefix, namespace);
} }
}
serializer.startTag(parser.getNamespace(), parser.getName()); serializer.startTag(parser.getNamespace(), parser.getName());
int attrCount = parser.getAttributeCount(); int attrCount = parser.getAttributeCount();
for(int i=0; i<attrCount; i++){ for(int i=0; i<attrCount; i++){
serializer.attribute(parser.getAttributeNamespace(i), String namespace = processNamespace ?
parser.getAttributeNamespace(i) : null;
serializer.attribute(namespace,
parser.getAttributeName(i), parser.getAttributeName(i),
parser.getAttributeValue(i)); parser.getAttributeValue(i));
} }
@ -98,4 +114,6 @@ public class XmlParserToSerializer {
private void onEndDocument() throws IOException{ private void onEndDocument() throws IOException{
serializer.endDocument(); serializer.endDocument();
} }
private static final String FEATURE_INDENT_OUTPUT = "http://xmlpull.org/v1/doc/features.html#indent-output";
} }