mirror of
https://github.com/revanced/ARSCLib.git
synced 2025-05-01 06:34:26 +02:00
create styled strings parser
This commit is contained in:
parent
472eb1c46c
commit
c49b04cc1b
@ -22,6 +22,15 @@ package com.reandroid.lib.apk.xmlencoder;
|
|||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
public class EncodeUtil {
|
public class EncodeUtil {
|
||||||
|
public static void sortStrings(List<String> stringList){
|
||||||
|
Comparator<String> cmp=new Comparator<String>() {
|
||||||
|
@Override
|
||||||
|
public int compare(String s1, String s2) {
|
||||||
|
return s1.compareTo(s2);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
stringList.sort(cmp);
|
||||||
|
}
|
||||||
public static void sortPublicXml(List<File> fileList){
|
public static void sortPublicXml(List<File> fileList){
|
||||||
Comparator<File> cmp=new Comparator<File>() {
|
Comparator<File> cmp=new Comparator<File>() {
|
||||||
@Override
|
@Override
|
||||||
|
@ -15,23 +15,75 @@
|
|||||||
*/
|
*/
|
||||||
package com.reandroid.lib.apk.xmlencoder;
|
package com.reandroid.lib.apk.xmlencoder;
|
||||||
|
|
||||||
|
import com.reandroid.lib.arsc.array.StyleArray;
|
||||||
import com.reandroid.lib.arsc.decoder.ValueDecoder;
|
import com.reandroid.lib.arsc.decoder.ValueDecoder;
|
||||||
|
import com.reandroid.lib.arsc.item.StyleItem;
|
||||||
|
import com.reandroid.lib.arsc.item.TableString;
|
||||||
import com.reandroid.lib.arsc.pool.TableStringPool;
|
import com.reandroid.lib.arsc.pool.TableStringPool;
|
||||||
import com.reandroid.xml.XMLDocument;
|
import com.reandroid.xml.XMLDocument;
|
||||||
import com.reandroid.xml.XMLElement;
|
import com.reandroid.xml.XMLElement;
|
||||||
|
import com.reandroid.xml.XMLSpanInfo;
|
||||||
|
import com.reandroid.xml.XMLSpannable;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.HashSet;
|
import java.util.*;
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
public class ValuesStringPoolBuilder {
|
public class ValuesStringPoolBuilder {
|
||||||
private final Set<String> stringList;
|
private final Set<String> stringList;
|
||||||
public ValuesStringPoolBuilder(){
|
public ValuesStringPoolBuilder(){
|
||||||
this.stringList=new HashSet<>();
|
this.stringList=new HashSet<>();
|
||||||
}
|
}
|
||||||
public void addTo(TableStringPool stringPool){
|
public void addTo(TableStringPool stringPool){
|
||||||
|
if(stringPool.getStringsArray().childesCount()==0){
|
||||||
|
buildWithStyles(stringPool);
|
||||||
|
}
|
||||||
stringPool.addStrings(stringList);
|
stringPool.addStrings(stringList);
|
||||||
stringList.clear();
|
stringList.clear();
|
||||||
|
stringPool.refresh();
|
||||||
|
}
|
||||||
|
private void buildWithStyles(TableStringPool stringPool){
|
||||||
|
List<XMLSpannable> spannableList = buildSpannable();
|
||||||
|
if(spannableList.size()==0){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, TableString> stringsMap = stringPool
|
||||||
|
.insertStrings(XMLSpannable.toTextList(spannableList));
|
||||||
|
|
||||||
|
List<String> tagList =
|
||||||
|
new ArrayList<>(XMLSpannable.tagList(spannableList));
|
||||||
|
EncodeUtil.sortStrings(tagList);
|
||||||
|
Map<String, TableString> tagsMap =
|
||||||
|
stringPool.insertStrings(tagList);
|
||||||
|
|
||||||
|
StyleArray styleArray = stringPool.getStyleArray();
|
||||||
|
styleArray.setChildesCount(stringsMap.size());
|
||||||
|
|
||||||
|
for(XMLSpannable spannable:spannableList){
|
||||||
|
|
||||||
|
TableString tableString=stringsMap.get(spannable.getText());
|
||||||
|
StyleItem styleItem = styleArray.get(tableString.getIndex());
|
||||||
|
|
||||||
|
for(XMLSpanInfo spanInfo:spannable.getSpanInfoList()){
|
||||||
|
int tagRef=tagsMap.get(spanInfo.tag).getIndex();
|
||||||
|
styleItem.addStylePiece(tagRef, spanInfo.start, spanInfo.end);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stringPool.refreshUniqueIdMap();
|
||||||
|
}
|
||||||
|
private List<XMLSpannable> buildSpannable(){
|
||||||
|
List<XMLSpannable> results=new ArrayList<>();
|
||||||
|
Set<String> removeList=new HashSet<>();
|
||||||
|
for(String text:stringList){
|
||||||
|
XMLSpannable spannable=XMLSpannable.parse(text);
|
||||||
|
if(spannable!=null){
|
||||||
|
results.add(spannable);
|
||||||
|
removeList.add(text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stringList.removeAll(removeList);
|
||||||
|
XMLSpannable.sort(results);
|
||||||
|
return results;
|
||||||
}
|
}
|
||||||
public void scanValuesDirectory(File dir){
|
public void scanValuesDirectory(File dir){
|
||||||
addStringsFile(new File(dir, "strings.xml"));
|
addStringsFile(new File(dir, "strings.xml"));
|
||||||
|
@ -102,9 +102,9 @@ public abstract class BaseStringPool<T extends StringItem> extends BaseChunk imp
|
|||||||
}
|
}
|
||||||
List<String> sortedList=new ArrayList<>(stringList);
|
List<String> sortedList=new ArrayList<>(stringList);
|
||||||
sortedList.sort(this);
|
sortedList.sort(this);
|
||||||
insertStrings(sortedList);
|
insertStringList(sortedList);
|
||||||
}
|
}
|
||||||
private void insertStrings(List<String> stringList){
|
private void insertStringList(List<String> stringList){
|
||||||
StringArray<T> stringsArray = getStringsArray();
|
StringArray<T> stringsArray = getStringsArray();
|
||||||
int initialSize=stringsArray.childesCount();
|
int initialSize=stringsArray.childesCount();
|
||||||
stringsArray.ensureSize(initialSize + stringList.size());
|
stringsArray.ensureSize(initialSize + stringList.size());
|
||||||
@ -117,6 +117,23 @@ public abstract class BaseStringPool<T extends StringItem> extends BaseChunk imp
|
|||||||
}
|
}
|
||||||
refreshUniqueIdMap();
|
refreshUniqueIdMap();
|
||||||
}
|
}
|
||||||
|
public Map<String, T> insertStrings(List<String> stringList){
|
||||||
|
Map<String, T> results=new HashMap<>();
|
||||||
|
StringArray<T> stringsArray = getStringsArray();
|
||||||
|
int initialSize=stringsArray.childesCount();
|
||||||
|
stringsArray.ensureSize(initialSize + stringList.size());
|
||||||
|
int size=stringsArray.childesCount();
|
||||||
|
int j=0;
|
||||||
|
for (int i=initialSize;i<size;i++){
|
||||||
|
T item=stringsArray.get(i);
|
||||||
|
String str=stringList.get(j);
|
||||||
|
item.set(str);
|
||||||
|
results.put(str, item);
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
refreshUniqueIdMap();
|
||||||
|
return results;
|
||||||
|
}
|
||||||
// call this after modifying string values
|
// call this after modifying string values
|
||||||
public void refreshUniqueIdMap(){
|
public void refreshUniqueIdMap(){
|
||||||
mUniqueMap.clear();
|
mUniqueMap.clear();
|
||||||
|
@ -20,20 +20,15 @@ import java.io.IOException;
|
|||||||
import java.io.StringWriter;
|
import java.io.StringWriter;
|
||||||
import java.io.Writer;
|
import java.io.Writer;
|
||||||
|
|
||||||
public class XMLAttribute {
|
public class XMLAttribute extends XMLNode{
|
||||||
private int mNameId;
|
private int mNameId;
|
||||||
private int mValueId;
|
private int mValueId;
|
||||||
private Object mValueTag;
|
|
||||||
private Object mNameTag;
|
|
||||||
private String mName;
|
private String mName;
|
||||||
private String mValue;
|
private String mValue;
|
||||||
public XMLAttribute(String name, String val){
|
public XMLAttribute(String name, String val){
|
||||||
mName=name;
|
mName=name;
|
||||||
mValue= XMLUtil.escapeXmlChars(val);
|
mValue= XMLUtil.escapeXmlChars(val);
|
||||||
}
|
}
|
||||||
public void setNameId(String id){
|
|
||||||
setNameId(XMLUtil.hexToInt(id,0));
|
|
||||||
}
|
|
||||||
public void setNameId(int id){
|
public void setNameId(int id){
|
||||||
mNameId=id;
|
mNameId=id;
|
||||||
}
|
}
|
||||||
@ -55,18 +50,6 @@ public class XMLAttribute {
|
|||||||
baseAttr.setValueId(getValueId());
|
baseAttr.setValueId(getValueId());
|
||||||
return baseAttr;
|
return baseAttr;
|
||||||
}
|
}
|
||||||
public Object getValueTag(){
|
|
||||||
return mValueTag;
|
|
||||||
}
|
|
||||||
public void setValueTag(Object obj){
|
|
||||||
mValueTag =obj;
|
|
||||||
}
|
|
||||||
public Object geNameTag(){
|
|
||||||
return mNameTag;
|
|
||||||
}
|
|
||||||
public void setNameTag(Object obj){
|
|
||||||
mNameTag =obj;
|
|
||||||
}
|
|
||||||
public String getName(){
|
public String getName(){
|
||||||
return mName;
|
return mName;
|
||||||
}
|
}
|
||||||
@ -117,19 +100,9 @@ public class XMLAttribute {
|
|||||||
public boolean isEmpty(){
|
public boolean isEmpty(){
|
||||||
return XMLUtil.isEmpty(getName());
|
return XMLUtil.isEmpty(getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object obj){
|
public boolean write(Writer writer, boolean newLineAttributes) throws IOException {
|
||||||
if(obj instanceof XMLAttribute){
|
|
||||||
XMLAttribute attr=(XMLAttribute)obj;
|
|
||||||
if(isEmpty()){
|
|
||||||
return attr.isEmpty();
|
|
||||||
}
|
|
||||||
String s=toString();
|
|
||||||
return s.equals(attr.toString());
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
public boolean write(Writer writer) throws IOException {
|
|
||||||
if(isEmpty()){
|
if(isEmpty()){
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -143,16 +116,40 @@ public class XMLAttribute {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public String toString(){
|
public String toText(int indent, boolean newLineAttributes) {
|
||||||
if(isEmpty()){
|
if(isEmpty()){
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
StringWriter writer=new StringWriter();
|
StringWriter writer=new StringWriter();
|
||||||
try {
|
try {
|
||||||
write(writer);
|
write(writer);
|
||||||
} catch (IOException e) {
|
} catch (IOException ignored) {
|
||||||
}
|
}
|
||||||
writer.flush();
|
writer.flush();
|
||||||
return writer.toString();
|
return writer.toString();
|
||||||
}
|
}
|
||||||
|
@Override
|
||||||
|
public int hashCode(){
|
||||||
|
String name=getName();
|
||||||
|
if(name==null){
|
||||||
|
name="";
|
||||||
|
}
|
||||||
|
name=getClass().getName()+name;
|
||||||
|
return name.hashCode();
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj){
|
||||||
|
if(obj instanceof XMLAttribute){
|
||||||
|
XMLAttribute attr=(XMLAttribute)obj;
|
||||||
|
if(isEmpty()){
|
||||||
|
return attr.isEmpty();
|
||||||
|
}
|
||||||
|
return getName().equals(attr.getName());
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public String toString(){
|
||||||
|
return toText();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -31,15 +31,7 @@ public class XMLComment extends XMLElement {
|
|||||||
super();
|
super();
|
||||||
initializeStartEnd();
|
initializeStartEnd();
|
||||||
}
|
}
|
||||||
@Override
|
|
||||||
XMLElement onCloneElement(){
|
|
||||||
XMLComment ce=new XMLComment(getCommentText());
|
|
||||||
ce.setHidden(isHidden());
|
|
||||||
return ce;
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
void cloneAllAttributes(XMLElement element){
|
|
||||||
}
|
|
||||||
public void setHidden(boolean hide){
|
public void setHidden(boolean hide){
|
||||||
mIsHidden=hide;
|
mIsHidden=hide;
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@ import java.io.*;
|
|||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
|
|
||||||
public class XMLDocument {
|
public class XMLDocument extends XMLNode{
|
||||||
private XMLElement mDocumentElement;
|
private XMLElement mDocumentElement;
|
||||||
private Object mTag;
|
private Object mTag;
|
||||||
private String mName;
|
private String mName;
|
||||||
@ -189,6 +189,7 @@ public class XMLDocument {
|
|||||||
writer.close();
|
writer.close();
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@Override
|
||||||
public boolean write(Writer writer, boolean newLineAttributes) throws IOException{
|
public boolean write(Writer writer, boolean newLineAttributes) throws IOException{
|
||||||
boolean has_header=appendDocumentAttribute(writer);
|
boolean has_header=appendDocumentAttribute(writer);
|
||||||
if(has_header){
|
if(has_header){
|
||||||
@ -196,12 +197,7 @@ public class XMLDocument {
|
|||||||
}
|
}
|
||||||
return appendDocumentElement(writer, newLineAttributes);
|
return appendDocumentElement(writer, newLineAttributes);
|
||||||
}
|
}
|
||||||
public String toText(){
|
@Override
|
||||||
return toText(1, false);
|
|
||||||
}
|
|
||||||
public String toText(boolean newLineAttributes){
|
|
||||||
return toText(1, newLineAttributes);
|
|
||||||
}
|
|
||||||
public String toText(int indent, boolean newLineAttributes){
|
public String toText(int indent, boolean newLineAttributes){
|
||||||
StringWriter writer=new StringWriter();
|
StringWriter writer=new StringWriter();
|
||||||
setIndent(indent);
|
setIndent(indent);
|
||||||
|
@ -21,20 +21,19 @@ import java.io.StringWriter;
|
|||||||
import java.io.Writer;
|
import java.io.Writer;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
public class XMLElement {
|
public class XMLElement extends XMLNode{
|
||||||
static final long DEBUG_TO_STRING=500;
|
static final long DEBUG_TO_STRING=500;
|
||||||
private String mTagName;
|
private String mTagName;
|
||||||
private XMLTextAttribute mTextAttribute;
|
private XMLTextAttribute mTextAttribute;
|
||||||
private List<XMLAttribute> mAttributes;
|
private final List<XMLAttribute> mAttributes = new ArrayList<>();
|
||||||
private List<XMLElement> mChildes;
|
private final List<XMLElement> mChildes = new ArrayList<>();
|
||||||
private List<XMLComment> mComments;
|
private List<XMLComment> mComments;
|
||||||
|
private final List<XMLText> mTexts = new ArrayList<>();
|
||||||
private XMLElement mParent;
|
private XMLElement mParent;
|
||||||
private int mIndent;
|
private int mIndent;
|
||||||
private Object mTag;
|
private Object mTag;
|
||||||
private int mResId;
|
private int mResId;
|
||||||
private float mIndentScale;
|
private float mIndentScale;
|
||||||
private String mUniqueAttrName;
|
|
||||||
private List<String> mUniqueNameValues;
|
|
||||||
private String mStart;
|
private String mStart;
|
||||||
private String mStartPrefix;
|
private String mStartPrefix;
|
||||||
private String mEnd;
|
private String mEnd;
|
||||||
@ -48,6 +47,19 @@ public class XMLElement {
|
|||||||
setDefaultStartEnd();
|
setDefaultStartEnd();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void addText(XMLText text){
|
||||||
|
if(text==null){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mTexts.add(text);
|
||||||
|
super.addChildNode(text);
|
||||||
|
}
|
||||||
|
private void appendText(String text){
|
||||||
|
if(text==null || text.length()==0){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
addText(new XMLText(text));
|
||||||
|
}
|
||||||
public String getTagNamePrefix(){
|
public String getTagNamePrefix(){
|
||||||
int i=mTagName.indexOf(":");
|
int i=mTagName.indexOf(":");
|
||||||
if(i>0){
|
if(i>0){
|
||||||
@ -68,45 +80,6 @@ public class XMLElement {
|
|||||||
this.mStartPrefix="/";
|
this.mStartPrefix="/";
|
||||||
this.mEndPrefix="/";
|
this.mEndPrefix="/";
|
||||||
}
|
}
|
||||||
public XMLElement removeChild(XMLElement element){
|
|
||||||
if(mChildes==null || element==null){
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
int i=mChildes.indexOf(element);
|
|
||||||
if(i<0){
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
XMLElement result=mChildes.get(i);
|
|
||||||
mChildes.remove(i);
|
|
||||||
result.setParent(null);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
public XMLElement getFirstChildWithAttrName(String name){
|
|
||||||
if(mChildes==null || name==null){
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
for(XMLElement element:mChildes){
|
|
||||||
XMLAttribute attr=element.getAttribute(name);
|
|
||||||
if(attr!=null){
|
|
||||||
return element;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
public XMLElement getFirstChildWithAttr(String attrName, String attrValue){
|
|
||||||
if(mChildes==null || attrName==null || attrValue==null){
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
for(XMLElement element:mChildes){
|
|
||||||
XMLAttribute attr=element.getAttribute(attrName);
|
|
||||||
if(attr!=null){
|
|
||||||
if(attrValue.equals(attr.getValue())){
|
|
||||||
return element;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
public void applyNameSpaceItems(){
|
public void applyNameSpaceItems(){
|
||||||
if(nameSpaceItems!=null){
|
if(nameSpaceItems!=null){
|
||||||
for(NameSpaceItem nsItem:nameSpaceItems){
|
for(NameSpaceItem nsItem:nameSpaceItems){
|
||||||
@ -162,82 +135,24 @@ public class XMLElement {
|
|||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
public void setStart(String start) {
|
void setStart(String start) {
|
||||||
this.mStart = start;
|
this.mStart = start;
|
||||||
}
|
}
|
||||||
public void setEnd(String end) {
|
void setEnd(String end) {
|
||||||
this.mEnd = end;
|
this.mEnd = end;
|
||||||
}
|
}
|
||||||
public void setStartPrefix(String pfx) {
|
void setStartPrefix(String pfx) {
|
||||||
if(pfx==null){
|
if(pfx==null){
|
||||||
pfx="";
|
pfx="";
|
||||||
}
|
}
|
||||||
this.mStartPrefix = pfx;
|
this.mStartPrefix = pfx;
|
||||||
}
|
}
|
||||||
public void setEndPrefix(String pfx) {
|
void setEndPrefix(String pfx) {
|
||||||
if(pfx==null){
|
if(pfx==null){
|
||||||
pfx="";
|
pfx="";
|
||||||
}
|
}
|
||||||
this.mEndPrefix = pfx;
|
this.mEndPrefix = pfx;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setUniqueAttrName(String attrName){
|
|
||||||
clearUniqueNameValues();
|
|
||||||
if(XMLUtil.isEmpty(attrName)){
|
|
||||||
mUniqueAttrName=null;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
mUniqueAttrName=attrName;
|
|
||||||
}
|
|
||||||
public String getUniqueAttrName(){
|
|
||||||
return mUniqueAttrName;
|
|
||||||
}
|
|
||||||
private void clearUniqueNameValues(){
|
|
||||||
if(mUniqueNameValues!=null){
|
|
||||||
mUniqueNameValues.clear();
|
|
||||||
mUniqueNameValues=null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private void addUniqueNameValues(XMLElement element){
|
|
||||||
if(element==null){
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
XMLAttribute baseAttr=element.getAttribute(getUniqueAttrName());
|
|
||||||
if(baseAttr==null){
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
addUniqueNameValues(baseAttr.getValue());
|
|
||||||
}
|
|
||||||
private void addUniqueNameValues(String nameVal){
|
|
||||||
if(XMLUtil.isEmpty(nameVal)){
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if(mUniqueNameValues==null){
|
|
||||||
mUniqueNameValues=new ArrayList<>();
|
|
||||||
}
|
|
||||||
mUniqueNameValues.add(nameVal);
|
|
||||||
}
|
|
||||||
private boolean shouldCheckUniqueElement(){
|
|
||||||
return mUniqueAttrName!=null;
|
|
||||||
}
|
|
||||||
private boolean containsUniqueNameValue(XMLElement element){
|
|
||||||
if(element==null){
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return containsUniqueNameValue(element.getAttribute(getUniqueAttrName()));
|
|
||||||
}
|
|
||||||
private boolean containsUniqueNameValue(XMLAttribute baseAttr){
|
|
||||||
if(baseAttr==null){
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return containsUniqueNameValue(baseAttr.getValue());
|
|
||||||
}
|
|
||||||
private boolean containsUniqueNameValue(String nameVal){
|
|
||||||
if(mUniqueNameValues==null|| XMLUtil.isEmpty(nameVal)){
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return mUniqueNameValues.contains(nameVal);
|
|
||||||
}
|
|
||||||
void setIndentScale(float scale){
|
void setIndentScale(float scale){
|
||||||
mIndentScale=scale;
|
mIndentScale=scale;
|
||||||
}
|
}
|
||||||
@ -254,82 +169,11 @@ public class XMLElement {
|
|||||||
public void setResourceId(int id){
|
public void setResourceId(int id){
|
||||||
mResId=id;
|
mResId=id;
|
||||||
}
|
}
|
||||||
public boolean containsSameChild(XMLElement baseElement){
|
|
||||||
if(baseElement==null||mChildes==null){
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
for(XMLElement ch:mChildes){
|
|
||||||
if(baseElement.isSame(ch)){
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
private String getUniqueId(){
|
|
||||||
StringBuilder builder=new StringBuilder(getTagName());
|
|
||||||
builder.append(attributesToString(false));
|
|
||||||
return builder.toString();
|
|
||||||
}
|
|
||||||
private boolean isSame(XMLElement baseElement){
|
|
||||||
if(baseElement==null){
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
String s1=getUniqueId();
|
|
||||||
String s2=baseElement.getUniqueId();
|
|
||||||
return XMLUtil.isStringEqual(s1,s2);
|
|
||||||
}
|
|
||||||
public XMLElement cloneElement(){
|
|
||||||
XMLElement baseElement=onCloneElement();
|
|
||||||
baseElement.setTag(getTag());
|
|
||||||
cloneAllAttributes(baseElement);
|
|
||||||
if(mChildes!=null){
|
|
||||||
for(XMLElement element:mChildes){
|
|
||||||
baseElement.addChildNoCheck(element.cloneElement());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(mComments!=null){
|
|
||||||
for(XMLComment ce:mComments){
|
|
||||||
baseElement.addComment((XMLComment) ce.cloneElement());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return baseElement;
|
|
||||||
}
|
|
||||||
void cloneAllAttributes(XMLElement element){
|
|
||||||
if(mAttributes!=null){
|
|
||||||
for(XMLAttribute attr:mAttributes){
|
|
||||||
element.addAttributeNoCheck(attr.cloneAttr());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
XMLTextAttribute textAttribute=mTextAttribute;
|
|
||||||
if(textAttribute!=null){
|
|
||||||
element.mTextAttribute=mTextAttribute.cloneAttr();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
XMLElement onCloneElement(){
|
|
||||||
return new XMLElement(getTagName());
|
|
||||||
}
|
|
||||||
public XMLElement createElement(String tag) {
|
public XMLElement createElement(String tag) {
|
||||||
XMLElement baseElement=new XMLElement(tag);
|
XMLElement baseElement=new XMLElement(tag);
|
||||||
addChildNoCheck(baseElement);
|
addChildNoCheck(baseElement);
|
||||||
return baseElement;
|
return baseElement;
|
||||||
}
|
}
|
||||||
public boolean containsChild(XMLElement baseElement){
|
|
||||||
if(baseElement==null||mChildes==null){
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return mChildes.contains(baseElement);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addChild(XMLElement[] elements) {
|
|
||||||
if(elements==null){
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
int max=elements.length;
|
|
||||||
for(int i=0;i<max;i++){
|
|
||||||
XMLElement baseElement=elements[i];
|
|
||||||
addChild(baseElement);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public void addChild(Collection<XMLElement> elements) {
|
public void addChild(Collection<XMLElement> elements) {
|
||||||
if(elements==null){
|
if(elements==null){
|
||||||
return;
|
return;
|
||||||
@ -338,8 +182,14 @@ public class XMLElement {
|
|||||||
addChild(element);
|
addChild(element);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public void addChild(XMLElement baseElement) {
|
public void addChild(XMLElement child) {
|
||||||
addChildNoCheck(baseElement);
|
addChildNoCheck(child);
|
||||||
|
}
|
||||||
|
private void clearChildElements(){
|
||||||
|
mChildes.clear();
|
||||||
|
}
|
||||||
|
private void clearTexts(){
|
||||||
|
mTexts.clear();
|
||||||
}
|
}
|
||||||
public XMLComment getCommentAt(int index){
|
public XMLComment getCommentAt(int index){
|
||||||
if(mComments==null || index<0){
|
if(mComments==null || index<0){
|
||||||
@ -352,7 +202,7 @@ public class XMLElement {
|
|||||||
}
|
}
|
||||||
public void hideComments(boolean recursive, boolean hide){
|
public void hideComments(boolean recursive, boolean hide){
|
||||||
hideComments(hide);
|
hideComments(hide);
|
||||||
if(recursive && mChildes!=null){
|
if(recursive){
|
||||||
for(XMLElement child:mChildes){
|
for(XMLElement child:mChildes){
|
||||||
child.hideComments(recursive, hide);
|
child.hideComments(recursive, hide);
|
||||||
}
|
}
|
||||||
@ -397,75 +247,30 @@ public class XMLElement {
|
|||||||
mComments.add(commentElement);
|
mComments.add(commentElement);
|
||||||
commentElement.setIndent(getIndent());
|
commentElement.setIndent(getIndent());
|
||||||
commentElement.setParent(this);
|
commentElement.setParent(this);
|
||||||
|
super.addChildNode(commentElement);
|
||||||
}
|
}
|
||||||
public void removeAllChildes(){
|
public void removeChildElements(){
|
||||||
if(mChildes==null){
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
mChildes.clear();
|
mChildes.clear();
|
||||||
}
|
}
|
||||||
public int getChildesCount(){
|
public List<XMLAttribute> listAttributes(){
|
||||||
if(mChildes==null){
|
return mAttributes;
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
public int getChildesCount(){
|
||||||
return mChildes.size();
|
return mChildes.size();
|
||||||
}
|
}
|
||||||
public XMLElement getFirstElementByTagName(String tagName){
|
public List<XMLElement> listChildElements(){
|
||||||
if(tagName==null||mChildes==null){
|
return mChildes;
|
||||||
return null;
|
|
||||||
}
|
|
||||||
for(XMLElement element:mChildes){
|
|
||||||
if(tagName.equals(element.getTagName())){
|
|
||||||
return element;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
public XMLElement[] getElementsByTagName(String tagName){
|
|
||||||
if(tagName==null||mChildes==null){
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
List<XMLElement> results=new ArrayList<>();
|
|
||||||
for(XMLElement element:mChildes){
|
|
||||||
if(tagName.equals(element.getTagName())){
|
|
||||||
results.add(element);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
int max=results.size();
|
|
||||||
if(max==0){
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return results.toArray(new XMLElement[max]);
|
|
||||||
}
|
|
||||||
public XMLElement[] getAllChildes(){
|
|
||||||
if(mChildes==null){
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
int max=mChildes.size();
|
|
||||||
if(max==0){
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return mChildes.toArray(new XMLElement[max]);
|
|
||||||
}
|
}
|
||||||
public XMLElement getChildAt(int index){
|
public XMLElement getChildAt(int index){
|
||||||
if(mChildes==null||index<0){
|
if(index<0 || index>=mChildes.size()){
|
||||||
return null;
|
|
||||||
}
|
|
||||||
if(index>=mChildes.size()){
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return mChildes.get(index);
|
return mChildes.get(index);
|
||||||
}
|
}
|
||||||
public int getAttributeCount(){
|
public int getAttributeCount(){
|
||||||
if(mAttributes==null){
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return mAttributes.size();
|
return mAttributes.size();
|
||||||
}
|
}
|
||||||
public XMLAttribute getAttributeAt(int index){
|
public XMLAttribute getAttributeAt(int index){
|
||||||
if(mAttributes==null||index<0){
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
if(index>=mAttributes.size()){
|
if(index>=mAttributes.size()){
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -514,9 +319,6 @@ public class XMLElement {
|
|||||||
return attr.getValueBool();
|
return attr.getValueBool();
|
||||||
}
|
}
|
||||||
public XMLAttribute getAttribute(String name){
|
public XMLAttribute getAttribute(String name){
|
||||||
if(mAttributes==null){
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
if(XMLUtil.isEmpty(name)){
|
if(XMLUtil.isEmpty(name)){
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -585,42 +387,22 @@ public class XMLElement {
|
|||||||
if(exist!=null){
|
if(exist!=null){
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(mAttributes==null){
|
|
||||||
mAttributes=new ArrayList<>();
|
|
||||||
}
|
|
||||||
mAttributes.add(attr);
|
mAttributes.add(attr);
|
||||||
}
|
}
|
||||||
private void addAttributeNoCheck(XMLAttribute attr){
|
private void addAttributeNoCheck(XMLAttribute attr){
|
||||||
if(attr==null){
|
if(attr==null || attr.isEmpty()){
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(XMLUtil.isEmpty(attr.getName())){
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if(mAttributes==null){
|
|
||||||
mAttributes=new ArrayList<>();
|
|
||||||
}
|
|
||||||
mAttributes.add(attr);
|
mAttributes.add(attr);
|
||||||
}
|
}
|
||||||
public void sortChildes(Comparator<XMLElement> comparator){
|
public void sortChildes(Comparator<XMLElement> comparator){
|
||||||
if(mChildes==null||comparator==null){
|
if(comparator==null){
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
mChildes.sort(comparator);
|
mChildes.sort(comparator);
|
||||||
}
|
}
|
||||||
public void sortAttributesWithChildes(Comparator<XMLAttribute> comparator){
|
|
||||||
if(comparator==null){
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
sortAttributes(comparator);
|
|
||||||
if(mChildes!=null){
|
|
||||||
for(XMLElement element:mChildes){
|
|
||||||
element.sortAttributesWithChildes(comparator);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public void sortAttributes(Comparator<XMLAttribute> comparator){
|
public void sortAttributes(Comparator<XMLAttribute> comparator){
|
||||||
if(mAttributes==null || comparator==null){
|
if(comparator==null){
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
mAttributes.sort(comparator);
|
mAttributes.sort(comparator);
|
||||||
@ -631,16 +413,14 @@ public class XMLElement {
|
|||||||
void setParent(XMLElement baseElement){
|
void setParent(XMLElement baseElement){
|
||||||
mParent=baseElement;
|
mParent=baseElement;
|
||||||
}
|
}
|
||||||
private void addChildNoCheck(XMLElement baseElement){
|
private void addChildNoCheck(XMLElement child){
|
||||||
if(baseElement==null){
|
if(child==null || child == this){
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(mChildes==null){
|
child.setParent(this);
|
||||||
mChildes=new ArrayList<>();
|
child.setIndent(getChildIndent());
|
||||||
}
|
mChildes.add(child);
|
||||||
baseElement.setParent(this);
|
super.addChildNode(child);
|
||||||
baseElement.setIndent(getChildIndent());
|
|
||||||
mChildes.add(baseElement);
|
|
||||||
}
|
}
|
||||||
public int getLevel(){
|
public int getLevel(){
|
||||||
int rs=0;
|
int rs=0;
|
||||||
@ -652,10 +432,13 @@ public class XMLElement {
|
|||||||
return rs;
|
return rs;
|
||||||
}
|
}
|
||||||
int getIndent(){
|
int getIndent(){
|
||||||
|
if(hasTextContent()){
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
return mIndent;
|
return mIndent;
|
||||||
}
|
}
|
||||||
int getChildIndent(){
|
int getChildIndent(){
|
||||||
if(mIndent<=0){
|
if(mIndent<=0 || hasTextContent()){
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
int rs=mIndent+1;
|
int rs=mIndent+1;
|
||||||
@ -671,11 +454,9 @@ public class XMLElement {
|
|||||||
}
|
}
|
||||||
public void setIndent(int indent){
|
public void setIndent(int indent){
|
||||||
mIndent=indent;
|
mIndent=indent;
|
||||||
if(mChildes!=null){
|
|
||||||
int chIndent=getChildIndent();
|
int chIndent=getChildIndent();
|
||||||
for(XMLElement be:mChildes){
|
for(XMLElement child:mChildes){
|
||||||
be.setIndent(chIndent);
|
child.setIndent(chIndent);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if(mComments!=null){
|
if(mComments!=null){
|
||||||
for(XMLComment ce:mComments){
|
for(XMLComment ce:mComments){
|
||||||
@ -683,22 +464,6 @@ public class XMLElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private String getAttributesIndentText(){
|
|
||||||
int i=getLevel()+1;
|
|
||||||
String tagName=getTagName();
|
|
||||||
if(tagName!=null){
|
|
||||||
i+=tagName.length();
|
|
||||||
}
|
|
||||||
if(i>12){
|
|
||||||
i=12;
|
|
||||||
}
|
|
||||||
tagName="";
|
|
||||||
while (tagName.length()<i){
|
|
||||||
tagName+=" ";
|
|
||||||
}
|
|
||||||
String rs=getIndentText();
|
|
||||||
return rs+tagName;
|
|
||||||
}
|
|
||||||
private boolean appendAttributesIndentText(Writer writer) throws IOException {
|
private boolean appendAttributesIndentText(Writer writer) throws IOException {
|
||||||
int i=0;
|
int i=0;
|
||||||
String tagName=getTagName();
|
String tagName=getTagName();
|
||||||
@ -770,18 +535,32 @@ public class XMLElement {
|
|||||||
mTag =tag;
|
mTag =tag;
|
||||||
}
|
}
|
||||||
public String getTextContent(){
|
public String getTextContent(){
|
||||||
return getTextContent(false);
|
return getTextContent(true);
|
||||||
}
|
}
|
||||||
public String getTextContent(boolean unEscape){
|
public String getTextContent(boolean unEscape){
|
||||||
XMLTextAttribute textAttribute= getTextAttr();
|
String text=buildTextContent();
|
||||||
return textAttribute.getText(unEscape);
|
if(unEscape){
|
||||||
|
text=XMLUtil.unEscapeXmlChars(text);
|
||||||
}
|
}
|
||||||
public XMLTextAttribute getTextAttribute(){
|
return text;
|
||||||
String txt=getTextContent();
|
}
|
||||||
if(txt==null){
|
private String buildTextContent(){
|
||||||
|
if(!hasTextContent()){
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return mTextAttribute;
|
StringWriter writer=new StringWriter();
|
||||||
|
for(XMLNode child:getChildNodes()){
|
||||||
|
try {
|
||||||
|
child.write(writer, false);
|
||||||
|
} catch (IOException ignored) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
writer.flush();
|
||||||
|
try {
|
||||||
|
writer.close();
|
||||||
|
} catch (IOException ignored) {
|
||||||
|
}
|
||||||
|
return writer.toString();
|
||||||
}
|
}
|
||||||
XMLTextAttribute getTextAttr(){
|
XMLTextAttribute getTextAttr(){
|
||||||
if(mTextAttribute==null){
|
if(mTextAttribute==null){
|
||||||
@ -789,43 +568,27 @@ public class XMLElement {
|
|||||||
}
|
}
|
||||||
return mTextAttribute;
|
return mTextAttribute;
|
||||||
}
|
}
|
||||||
private boolean appendTextContent(Writer writer) throws IOException {
|
private void appendTextContent(Writer writer) throws IOException {
|
||||||
if(mTextAttribute==null){
|
for(XMLNode child:getChildNodes()){
|
||||||
return false;
|
if(child instanceof XMLElement){
|
||||||
|
((XMLElement)child).setIndent(0);
|
||||||
}
|
}
|
||||||
return mTextAttribute.write(writer);
|
child.write(writer, false);
|
||||||
}
|
|
||||||
private boolean hasTextContent() {
|
|
||||||
if(mTextAttribute==null){
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return !mTextAttribute.isEmpty();
|
|
||||||
}
|
|
||||||
private void appendText(String text){
|
|
||||||
String old= getTextContent();
|
|
||||||
if (old!=null){
|
|
||||||
if(text!=null){
|
|
||||||
setTextContent(old+text);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
setTextContent(text);
|
public boolean hasTextContent() {
|
||||||
|
return mTexts.size()>0;
|
||||||
}
|
}
|
||||||
public XMLAttribute setTextContent(String text){
|
public void setTextContent(String text){
|
||||||
return setTextContent(text, true);
|
setTextContent(text, true);
|
||||||
}
|
}
|
||||||
public XMLAttribute setTextContent(String text, boolean escape){
|
public void setTextContent(String text, boolean escape){
|
||||||
XMLTextAttribute textAttribute= getTextAttr();
|
clearChildElements();
|
||||||
if(XMLUtil.isEmpty(text)){
|
clearTexts();
|
||||||
textAttribute.setText(null);
|
|
||||||
//textAttribute.setText(text);
|
|
||||||
}else {
|
|
||||||
if(escape){
|
if(escape){
|
||||||
text= XMLUtil.escapeXmlChars(text);
|
text=XMLUtil.escapeXmlChars(text);
|
||||||
}
|
}
|
||||||
textAttribute.setText(text);
|
appendText(text);
|
||||||
}
|
|
||||||
return textAttribute;
|
|
||||||
}
|
}
|
||||||
private boolean appendAttributes(Writer writer, boolean newLineAttributes) throws IOException {
|
private boolean appendAttributes(Writer writer, boolean newLineAttributes) throws IOException {
|
||||||
if(mAttributes==null){
|
if(mAttributes==null){
|
||||||
@ -851,50 +614,24 @@ public class XMLElement {
|
|||||||
}
|
}
|
||||||
return addedOnce;
|
return addedOnce;
|
||||||
}
|
}
|
||||||
private String attributesToString(boolean newLineAttributes){
|
|
||||||
if(mAttributes==null){
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
StringBuilder builder=new StringBuilder();
|
|
||||||
boolean addedOnce=false;
|
|
||||||
for(XMLAttribute attr:mAttributes){
|
|
||||||
if(attr.isEmpty()){
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if(addedOnce){
|
|
||||||
if(newLineAttributes){
|
|
||||||
builder.append("\n");
|
|
||||||
builder.append(getAttributesIndentText());
|
|
||||||
}else{
|
|
||||||
builder.append(" ");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
builder.append(attr.toString());
|
|
||||||
addedOnce=true;
|
|
||||||
}
|
|
||||||
if(addedOnce){
|
|
||||||
return builder.toString();
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
boolean isEmpty(){
|
boolean isEmpty(){
|
||||||
if(mTagName!=null){
|
if(mTagName!=null){
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if(mAttributes!=null && mAttributes.size()>0){
|
if(mAttributes.size()>0){
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if(mComments!=null && mComments.size()>0){
|
if(mComments!=null && mComments.size()>0){
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return getTextContent()==null;
|
if(mTexts.size()>0){
|
||||||
}
|
|
||||||
private boolean canAppendChildes(){
|
|
||||||
if(mChildes==null){
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
for(XMLElement be:mChildes){
|
return true;
|
||||||
if (!be.isEmpty()){
|
}
|
||||||
|
private boolean canAppendChildes(){
|
||||||
|
for(XMLElement child:mChildes){
|
||||||
|
if (!child.isEmpty()){
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -921,22 +658,19 @@ public class XMLElement {
|
|||||||
return addedOnce;
|
return addedOnce;
|
||||||
}
|
}
|
||||||
private boolean appendChildes(Writer writer, boolean newLineAttributes) throws IOException {
|
private boolean appendChildes(Writer writer, boolean newLineAttributes) throws IOException {
|
||||||
if(mChildes==null){
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
boolean appendPrevious=true;
|
boolean appendPrevious=true;
|
||||||
boolean addedOnce=false;
|
boolean addedOnce=false;
|
||||||
for(XMLElement be:mChildes){
|
for(XMLElement child:mChildes){
|
||||||
if(stopWriting(writer)){
|
if(stopWriting(writer)){
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if(be.isEmpty()){
|
if(child.isEmpty()){
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if(appendPrevious){
|
if(appendPrevious){
|
||||||
writer.write(XMLUtil.NEW_LINE);
|
writer.write(XMLUtil.NEW_LINE);
|
||||||
}
|
}
|
||||||
appendPrevious=be.write(writer, newLineAttributes);
|
appendPrevious=child.write(writer, newLineAttributes);
|
||||||
if(!addedOnce && appendPrevious){
|
if(!addedOnce && appendPrevious){
|
||||||
addedOnce=true;
|
addedOnce=true;
|
||||||
}
|
}
|
||||||
@ -954,6 +688,7 @@ public class XMLElement {
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@Override
|
||||||
public boolean write(Writer writer, boolean newLineAttributes) throws IOException {
|
public boolean write(Writer writer, boolean newLineAttributes) throws IOException {
|
||||||
if(isEmpty()){
|
if(isEmpty()){
|
||||||
return false;
|
return false;
|
||||||
@ -973,20 +708,15 @@ public class XMLElement {
|
|||||||
}
|
}
|
||||||
appendAttributes(writer, newLineAttributes);
|
appendAttributes(writer, newLineAttributes);
|
||||||
boolean useEndTag=false;
|
boolean useEndTag=false;
|
||||||
if(canAppendChildes()){
|
|
||||||
writer.write(mEnd);
|
|
||||||
appendChildes(writer, newLineAttributes);
|
|
||||||
useEndTag=true;
|
|
||||||
}
|
|
||||||
boolean hasTextCon=hasTextContent();
|
boolean hasTextCon=hasTextContent();
|
||||||
if(hasTextCon){
|
if(hasTextCon){
|
||||||
if(!useEndTag){
|
|
||||||
writer.write(mEnd);
|
writer.write(mEnd);
|
||||||
}else {
|
|
||||||
writer.write(XMLUtil.NEW_LINE);
|
|
||||||
}
|
|
||||||
appendTextContent(writer);
|
appendTextContent(writer);
|
||||||
useEndTag=true;
|
useEndTag=true;
|
||||||
|
}else if(canAppendChildes()){
|
||||||
|
writer.write(mEnd);
|
||||||
|
appendChildes(writer, newLineAttributes);
|
||||||
|
useEndTag=true;
|
||||||
}
|
}
|
||||||
if(useEndTag){
|
if(useEndTag){
|
||||||
if(!hasTextCon){
|
if(!hasTextCon){
|
||||||
@ -996,19 +726,13 @@ public class XMLElement {
|
|||||||
writer.write(mStart);
|
writer.write(mStart);
|
||||||
writer.write(mStartPrefix);
|
writer.write(mStartPrefix);
|
||||||
writer.write(getTagName());
|
writer.write(getTagName());
|
||||||
writer.write(mEnd);
|
|
||||||
}else {
|
}else {
|
||||||
writer.write(mEndPrefix);
|
writer.write(mEndPrefix);
|
||||||
writer.write(mEnd);
|
|
||||||
}
|
}
|
||||||
|
writer.write(mEnd);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
public String toText(){
|
@Override
|
||||||
return toText(1, false);
|
|
||||||
}
|
|
||||||
public String toText(boolean newLineAttributes){
|
|
||||||
return toText(1, newLineAttributes);
|
|
||||||
}
|
|
||||||
public String toText(int indent, boolean newLineAttributes){
|
public String toText(int indent, boolean newLineAttributes){
|
||||||
StringWriter writer=new StringWriter();
|
StringWriter writer=new StringWriter();
|
||||||
setIndent(indent);
|
setIndent(indent);
|
||||||
@ -1020,6 +744,24 @@ public class XMLElement {
|
|||||||
}
|
}
|
||||||
return writer.toString();
|
return writer.toString();
|
||||||
}
|
}
|
||||||
|
protected List<XMLNode> listSpannable(){
|
||||||
|
List<XMLNode> results = new ArrayList<>();
|
||||||
|
for(XMLNode child:getChildNodes()){
|
||||||
|
if((child instanceof XMLElement) || (child instanceof XMLText)){
|
||||||
|
results.add(child);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
protected String getSpannableText() {
|
||||||
|
StringBuilder builder = new StringBuilder();
|
||||||
|
builder.append(getTagName());
|
||||||
|
for(XMLAttribute attribute:listAttributes()){
|
||||||
|
builder.append(' ');
|
||||||
|
builder.append(attribute.toText(0, false));
|
||||||
|
}
|
||||||
|
return builder.toString();
|
||||||
|
}
|
||||||
@Override
|
@Override
|
||||||
public String toString(){
|
public String toString(){
|
||||||
StringWriter strWriter=new StringWriter();
|
StringWriter strWriter=new StringWriter();
|
||||||
@ -1032,23 +774,4 @@ public class XMLElement {
|
|||||||
return strWriter.toString();
|
return strWriter.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<XMLElement> getAllElementsRecursive(XMLElement parent){
|
|
||||||
List<XMLElement> results=new ArrayList<>();
|
|
||||||
if(parent==null){
|
|
||||||
return results;
|
|
||||||
}
|
|
||||||
XMLElement[] allChildes=parent.getAllChildes();
|
|
||||||
if(allChildes==null){
|
|
||||||
return results;
|
|
||||||
}
|
|
||||||
int max=allChildes.length;
|
|
||||||
for(int i=0;i<max;i++){
|
|
||||||
XMLElement child=allChildes[i];
|
|
||||||
results.add(child);
|
|
||||||
results.addAll(getAllElementsRecursive(child));
|
|
||||||
}
|
|
||||||
return results;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
58
src/main/java/com/reandroid/xml/XMLNode.java
Normal file
58
src/main/java/com/reandroid/xml/XMLNode.java
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 github.com/REAndroid
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.reandroid.xml;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.Writer;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public abstract class XMLNode {
|
||||||
|
private final List<XMLNode> mChildNodes = new ArrayList<>();
|
||||||
|
|
||||||
|
void addChildNode(XMLNode xmlNode){
|
||||||
|
if(xmlNode!=null && canAdd(xmlNode)){
|
||||||
|
mChildNodes.add(xmlNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
boolean canAdd(XMLNode xmlNode){
|
||||||
|
return !mChildNodes.contains(xmlNode);
|
||||||
|
}
|
||||||
|
boolean contains(XMLNode xmlNode){
|
||||||
|
return mChildNodes.contains(xmlNode);
|
||||||
|
}
|
||||||
|
void removeChildNode(XMLNode xmlNode){
|
||||||
|
int i = mChildNodes.indexOf(xmlNode);
|
||||||
|
while (i>=0){
|
||||||
|
i = mChildNodes.indexOf(xmlNode);
|
||||||
|
}
|
||||||
|
mChildNodes.remove(xmlNode);
|
||||||
|
}
|
||||||
|
public List<XMLNode> getChildNodes() {
|
||||||
|
return mChildNodes;
|
||||||
|
}
|
||||||
|
public boolean write(Writer writer) throws IOException {
|
||||||
|
return write(writer, false);
|
||||||
|
}
|
||||||
|
public String toText(){
|
||||||
|
return toText(1, false);
|
||||||
|
}
|
||||||
|
public String toText(boolean newLineAttributes){
|
||||||
|
return toText(1, newLineAttributes);
|
||||||
|
}
|
||||||
|
public abstract boolean write(Writer writer, boolean newLineAttributes) throws IOException;
|
||||||
|
public abstract String toText(int indent, boolean newLineAttributes);
|
||||||
|
}
|
27
src/main/java/com/reandroid/xml/XMLSpanInfo.java
Normal file
27
src/main/java/com/reandroid/xml/XMLSpanInfo.java
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 github.com/REAndroid
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.reandroid.xml;
|
||||||
|
|
||||||
|
public class XMLSpanInfo {
|
||||||
|
public final String tag;
|
||||||
|
public final int start;
|
||||||
|
public int end;
|
||||||
|
public XMLSpanInfo(String tag, int start, int end){
|
||||||
|
this.tag=tag;
|
||||||
|
this.start=start;
|
||||||
|
this.end=end;
|
||||||
|
}
|
||||||
|
}
|
139
src/main/java/com/reandroid/xml/XMLSpannable.java
Normal file
139
src/main/java/com/reandroid/xml/XMLSpannable.java
Normal file
@ -0,0 +1,139 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 github.com/REAndroid
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.reandroid.xml;
|
||||||
|
|
||||||
|
import com.reandroid.xml.parser.XMLSpanParser;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
public class XMLSpannable implements Comparable<XMLSpannable>{
|
||||||
|
private XMLElement mElement;
|
||||||
|
private String mText;
|
||||||
|
private List<XMLSpanInfo> mSpanInfoList;
|
||||||
|
private XMLSpannable(XMLElement element){
|
||||||
|
this.mElement=element;
|
||||||
|
}
|
||||||
|
public boolean isValid(){
|
||||||
|
List<XMLSpanInfo> spanInfoList = getSpanInfoList();
|
||||||
|
if(spanInfoList.size()==0){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for(XMLSpanInfo spanInfo:spanInfoList){
|
||||||
|
if(spanInfo.end<spanInfo.start){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
public String getText(){
|
||||||
|
if(mText==null){
|
||||||
|
buildSpanInfo();
|
||||||
|
}
|
||||||
|
return mText;
|
||||||
|
}
|
||||||
|
public List<XMLSpanInfo> getSpanInfoList(){
|
||||||
|
if(mSpanInfoList==null){
|
||||||
|
buildSpanInfo();
|
||||||
|
}
|
||||||
|
return mSpanInfoList;
|
||||||
|
}
|
||||||
|
private void buildSpanInfo(){
|
||||||
|
mSpanInfoList=new ArrayList<>();
|
||||||
|
StringBuilder builder=new StringBuilder();
|
||||||
|
buildSpanInfo(mElement, builder);
|
||||||
|
mText=builder.toString();
|
||||||
|
mElement=null;
|
||||||
|
}
|
||||||
|
private void buildSpanInfo(XMLElement element, StringBuilder builder){
|
||||||
|
XMLSpanInfo info=null;
|
||||||
|
for(XMLNode node:element.listSpannable()){
|
||||||
|
if(info!=null){
|
||||||
|
info.end=builder.length();
|
||||||
|
info=null;
|
||||||
|
}
|
||||||
|
if(node instanceof XMLText){
|
||||||
|
builder.append(((XMLText)node).getText());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
XMLElement child = (XMLElement) node;
|
||||||
|
info=new XMLSpanInfo(
|
||||||
|
child.getSpannableText(),
|
||||||
|
builder.length(), 0);
|
||||||
|
mSpanInfoList.add(info);
|
||||||
|
buildSpanInfo(child, builder);
|
||||||
|
}
|
||||||
|
if(info!=null){
|
||||||
|
info.end=builder.length();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public int compareTo(XMLSpannable xmlSpannable) {
|
||||||
|
return getText().compareTo(xmlSpannable.getText());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static XMLSpannable parse(String text){
|
||||||
|
if(!hasStyle(text)){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
XMLSpannable spannable=new XMLSpannable(PARSER.parse(text));
|
||||||
|
if(spannable.isValid()){
|
||||||
|
return spannable;
|
||||||
|
}
|
||||||
|
} catch (Exception ignored) {
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
public static Set<String> tagList(Collection<XMLSpannable> spannableList){
|
||||||
|
Set<String> results=new HashSet<>();
|
||||||
|
for(XMLSpannable xmlSpannable:spannableList){
|
||||||
|
for(XMLSpanInfo spanInfo: xmlSpannable.getSpanInfoList()){
|
||||||
|
results.add(spanInfo.tag);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
public static List<String> toTextList(Collection<XMLSpannable> spannableList){
|
||||||
|
List<String> results=new ArrayList<>(spannableList.size());
|
||||||
|
for(XMLSpannable xmlSpannable:spannableList){
|
||||||
|
results.add(xmlSpannable.getText());
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
public static void sort(List<XMLSpannable> spannableList){
|
||||||
|
Comparator<XMLSpannable> cmp=new Comparator<XMLSpannable>() {
|
||||||
|
@Override
|
||||||
|
public int compare(XMLSpannable s1, XMLSpannable s2) {
|
||||||
|
return s1.compareTo(s2);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
spannableList.sort(cmp);
|
||||||
|
}
|
||||||
|
private static boolean hasStyle(String text){
|
||||||
|
if(text==null){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
int i=text.indexOf('<');
|
||||||
|
if(i<0){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
i=text.indexOf('>');
|
||||||
|
return i>1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final XMLSpanParser PARSER=new XMLSpanParser();
|
||||||
|
|
||||||
|
}
|
57
src/main/java/com/reandroid/xml/XMLText.java
Normal file
57
src/main/java/com/reandroid/xml/XMLText.java
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 github.com/REAndroid
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.reandroid.xml;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.Writer;
|
||||||
|
|
||||||
|
public class XMLText extends XMLNode{
|
||||||
|
private String text;
|
||||||
|
public XMLText(String text){
|
||||||
|
this.text=text;
|
||||||
|
}
|
||||||
|
public XMLText(){
|
||||||
|
this(null);
|
||||||
|
}
|
||||||
|
public String getText(){
|
||||||
|
return getText(true);
|
||||||
|
}
|
||||||
|
public String getText(boolean unEscape){
|
||||||
|
if(unEscape){
|
||||||
|
return XMLUtil.unEscapeXmlChars(text);
|
||||||
|
}
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
public void setText(String text){
|
||||||
|
this.text=XMLUtil.escapeXmlChars(text);
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public boolean write(Writer writer, boolean newLineAttributes) throws IOException {
|
||||||
|
if(!XMLUtil.isEmpty(this.text)){
|
||||||
|
writer.write(this.text);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public String toText(int indent, boolean newLineAttributes) {
|
||||||
|
return getText(false);
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public String toString(){
|
||||||
|
return getText();
|
||||||
|
}
|
||||||
|
}
|
@ -28,13 +28,6 @@ public class XmlHeaderElement extends XMLElement {
|
|||||||
initializeStartEnd();
|
initializeStartEnd();
|
||||||
setDefaultAttr();
|
setDefaultAttr();
|
||||||
}
|
}
|
||||||
@Override
|
|
||||||
XMLElement onCloneElement(){
|
|
||||||
return new XmlHeaderElement(this);
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
void cloneAllAttributes(XMLElement element){
|
|
||||||
}
|
|
||||||
private void copyAll(XmlHeaderElement element){
|
private void copyAll(XmlHeaderElement element){
|
||||||
if(element==null){
|
if(element==null){
|
||||||
return;
|
return;
|
||||||
|
@ -260,10 +260,10 @@ public class XMLDocumentParser {
|
|||||||
}
|
}
|
||||||
String text=mCurrentText.toString();
|
String text=mCurrentText.toString();
|
||||||
mCurrentText=null;
|
mCurrentText=null;
|
||||||
if(XMLUtil.isEmpty(text)){
|
if(text.trim().length()==0 && !mCurrentElement.hasTextContent()){
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
mCurrentElement.setTextContent(text, true);
|
mCurrentElement.addText(new XMLText(text));
|
||||||
}
|
}
|
||||||
private void onEntityRef(){
|
private void onEntityRef(){
|
||||||
String name=mParser.getName();
|
String name=mParser.getName();
|
||||||
|
98
src/main/java/com/reandroid/xml/parser/XMLSpanParser.java
Normal file
98
src/main/java/com/reandroid/xml/parser/XMLSpanParser.java
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 github.com/REAndroid
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.reandroid.xml.parser;
|
||||||
|
|
||||||
|
import com.reandroid.xml.*;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.StringReader;
|
||||||
|
|
||||||
|
public class XMLSpanParser {
|
||||||
|
private final XmlPullParser mParser;
|
||||||
|
private XMLElement mCurrentElement;
|
||||||
|
public XMLSpanParser(){
|
||||||
|
this.mParser = new MXParserNonValidating();
|
||||||
|
}
|
||||||
|
public XMLElement parse(String text) throws XMLException {
|
||||||
|
try {
|
||||||
|
text="<spannable-parser>"+text+"</spannable-parser>";
|
||||||
|
parseString(text);
|
||||||
|
} catch (XmlPullParserException|IOException ex) {
|
||||||
|
throw new XMLException(ex.getMessage());
|
||||||
|
}
|
||||||
|
XMLElement element=mCurrentElement;
|
||||||
|
mCurrentElement=null;
|
||||||
|
return element;
|
||||||
|
}
|
||||||
|
private void parseString(String text) throws XmlPullParserException, IOException {
|
||||||
|
mCurrentElement=null;
|
||||||
|
StringReader reader=new StringReader(text);
|
||||||
|
this.mParser.setInput(reader);
|
||||||
|
int type;
|
||||||
|
while ((type=mParser.nextToken()) !=XmlPullParser.END_DOCUMENT){
|
||||||
|
event(type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private void event(int type) {
|
||||||
|
if (type == XmlPullParser.START_DOCUMENT){
|
||||||
|
onStartDocument();
|
||||||
|
}else if (type == XmlPullParser.START_TAG){
|
||||||
|
onStartTag();
|
||||||
|
}else if (type == XmlPullParser.END_TAG){
|
||||||
|
onEndTag();
|
||||||
|
}else if (type == XmlPullParser.TEXT){
|
||||||
|
onText();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void loadAttributes(){
|
||||||
|
int max=mParser.getAttributeCount();
|
||||||
|
for(int i=0; i<max; i++){
|
||||||
|
onAttribute(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private void onAttribute(int i){
|
||||||
|
String attrName=mParser.getAttributeName(i);
|
||||||
|
String attrValue=mParser.getAttributeValue(i);
|
||||||
|
mCurrentElement.setAttribute(attrName, attrValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onStartTag() {
|
||||||
|
String name=mParser.getName();
|
||||||
|
if(mCurrentElement==null){
|
||||||
|
mCurrentElement=new XMLElement(name);
|
||||||
|
}else {
|
||||||
|
mCurrentElement=mCurrentElement.createElement(name);
|
||||||
|
}
|
||||||
|
loadAttributes();
|
||||||
|
}
|
||||||
|
private void onEndTag() {
|
||||||
|
XMLElement parent=mCurrentElement.getParent();
|
||||||
|
if(parent!=null){
|
||||||
|
mCurrentElement=parent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private void onText() {
|
||||||
|
String text=mParser.getText();
|
||||||
|
if(text!=null && text.length()>0){
|
||||||
|
mCurrentElement.addText(new XMLText(text));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private void onStartDocument() {
|
||||||
|
this.mCurrentElement=null;
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user