mirror of
https://github.com/revanced/ARSCLib.git
synced 2025-04-30 22:34:24 +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;
|
||||
|
||||
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){
|
||||
Comparator<File> cmp=new Comparator<File>() {
|
||||
@Override
|
||||
|
@ -15,14 +15,18 @@
|
||||
*/
|
||||
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.item.StyleItem;
|
||||
import com.reandroid.lib.arsc.item.TableString;
|
||||
import com.reandroid.lib.arsc.pool.TableStringPool;
|
||||
import com.reandroid.xml.XMLDocument;
|
||||
import com.reandroid.xml.XMLElement;
|
||||
import com.reandroid.xml.XMLSpanInfo;
|
||||
import com.reandroid.xml.XMLSpannable;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
|
||||
public class ValuesStringPoolBuilder {
|
||||
private final Set<String> stringList;
|
||||
@ -30,8 +34,56 @@ public class ValuesStringPoolBuilder {
|
||||
this.stringList=new HashSet<>();
|
||||
}
|
||||
public void addTo(TableStringPool stringPool){
|
||||
if(stringPool.getStringsArray().childesCount()==0){
|
||||
buildWithStyles(stringPool);
|
||||
}
|
||||
stringPool.addStrings(stringList);
|
||||
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){
|
||||
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);
|
||||
sortedList.sort(this);
|
||||
insertStrings(sortedList);
|
||||
insertStringList(sortedList);
|
||||
}
|
||||
private void insertStrings(List<String> stringList){
|
||||
private void insertStringList(List<String> stringList){
|
||||
StringArray<T> stringsArray = getStringsArray();
|
||||
int initialSize=stringsArray.childesCount();
|
||||
stringsArray.ensureSize(initialSize + stringList.size());
|
||||
@ -117,6 +117,23 @@ public abstract class BaseStringPool<T extends StringItem> extends BaseChunk imp
|
||||
}
|
||||
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
|
||||
public void refreshUniqueIdMap(){
|
||||
mUniqueMap.clear();
|
||||
|
@ -20,20 +20,15 @@ import java.io.IOException;
|
||||
import java.io.StringWriter;
|
||||
import java.io.Writer;
|
||||
|
||||
public class XMLAttribute {
|
||||
public class XMLAttribute extends XMLNode{
|
||||
private int mNameId;
|
||||
private int mValueId;
|
||||
private Object mValueTag;
|
||||
private Object mNameTag;
|
||||
private String mName;
|
||||
private String mValue;
|
||||
public XMLAttribute(String name, String val){
|
||||
mName=name;
|
||||
mValue= XMLUtil.escapeXmlChars(val);
|
||||
}
|
||||
public void setNameId(String id){
|
||||
setNameId(XMLUtil.hexToInt(id,0));
|
||||
}
|
||||
public void setNameId(int id){
|
||||
mNameId=id;
|
||||
}
|
||||
@ -55,18 +50,6 @@ public class XMLAttribute {
|
||||
baseAttr.setValueId(getValueId());
|
||||
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(){
|
||||
return mName;
|
||||
}
|
||||
@ -117,19 +100,9 @@ public class XMLAttribute {
|
||||
public boolean isEmpty(){
|
||||
return XMLUtil.isEmpty(getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj){
|
||||
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 {
|
||||
public boolean write(Writer writer, boolean newLineAttributes) throws IOException {
|
||||
if(isEmpty()){
|
||||
return false;
|
||||
}
|
||||
@ -143,16 +116,40 @@ public class XMLAttribute {
|
||||
return true;
|
||||
}
|
||||
@Override
|
||||
public String toString(){
|
||||
public String toText(int indent, boolean newLineAttributes) {
|
||||
if(isEmpty()){
|
||||
return null;
|
||||
}
|
||||
StringWriter writer=new StringWriter();
|
||||
try {
|
||||
write(writer);
|
||||
} catch (IOException e) {
|
||||
} catch (IOException ignored) {
|
||||
}
|
||||
writer.flush();
|
||||
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();
|
||||
initializeStartEnd();
|
||||
}
|
||||
@Override
|
||||
XMLElement onCloneElement(){
|
||||
XMLComment ce=new XMLComment(getCommentText());
|
||||
ce.setHidden(isHidden());
|
||||
return ce;
|
||||
}
|
||||
@Override
|
||||
void cloneAllAttributes(XMLElement element){
|
||||
}
|
||||
|
||||
public void setHidden(boolean hide){
|
||||
mIsHidden=hide;
|
||||
}
|
||||
|
@ -20,7 +20,7 @@ import java.io.*;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Comparator;
|
||||
|
||||
public class XMLDocument {
|
||||
public class XMLDocument extends XMLNode{
|
||||
private XMLElement mDocumentElement;
|
||||
private Object mTag;
|
||||
private String mName;
|
||||
@ -189,6 +189,7 @@ public class XMLDocument {
|
||||
writer.close();
|
||||
return result;
|
||||
}
|
||||
@Override
|
||||
public boolean write(Writer writer, boolean newLineAttributes) throws IOException{
|
||||
boolean has_header=appendDocumentAttribute(writer);
|
||||
if(has_header){
|
||||
@ -196,12 +197,7 @@ public class XMLDocument {
|
||||
}
|
||||
return appendDocumentElement(writer, newLineAttributes);
|
||||
}
|
||||
public String toText(){
|
||||
return toText(1, false);
|
||||
}
|
||||
public String toText(boolean newLineAttributes){
|
||||
return toText(1, newLineAttributes);
|
||||
}
|
||||
@Override
|
||||
public String toText(int indent, boolean newLineAttributes){
|
||||
StringWriter writer=new StringWriter();
|
||||
setIndent(indent);
|
||||
|
@ -21,20 +21,19 @@ import java.io.StringWriter;
|
||||
import java.io.Writer;
|
||||
import java.util.*;
|
||||
|
||||
public class XMLElement {
|
||||
public class XMLElement extends XMLNode{
|
||||
static final long DEBUG_TO_STRING=500;
|
||||
private String mTagName;
|
||||
private XMLTextAttribute mTextAttribute;
|
||||
private List<XMLAttribute> mAttributes;
|
||||
private List<XMLElement> mChildes;
|
||||
private final List<XMLAttribute> mAttributes = new ArrayList<>();
|
||||
private final List<XMLElement> mChildes = new ArrayList<>();
|
||||
private List<XMLComment> mComments;
|
||||
private final List<XMLText> mTexts = new ArrayList<>();
|
||||
private XMLElement mParent;
|
||||
private int mIndent;
|
||||
private Object mTag;
|
||||
private int mResId;
|
||||
private float mIndentScale;
|
||||
private String mUniqueAttrName;
|
||||
private List<String> mUniqueNameValues;
|
||||
private String mStart;
|
||||
private String mStartPrefix;
|
||||
private String mEnd;
|
||||
@ -48,6 +47,19 @@ public class XMLElement {
|
||||
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(){
|
||||
int i=mTagName.indexOf(":");
|
||||
if(i>0){
|
||||
@ -68,45 +80,6 @@ public class XMLElement {
|
||||
this.mStartPrefix="/";
|
||||
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(){
|
||||
if(nameSpaceItems!=null){
|
||||
for(NameSpaceItem nsItem:nameSpaceItems){
|
||||
@ -162,82 +135,24 @@ public class XMLElement {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
public void setStart(String start) {
|
||||
void setStart(String start) {
|
||||
this.mStart = start;
|
||||
}
|
||||
public void setEnd(String end) {
|
||||
void setEnd(String end) {
|
||||
this.mEnd = end;
|
||||
}
|
||||
public void setStartPrefix(String pfx) {
|
||||
void setStartPrefix(String pfx) {
|
||||
if(pfx==null){
|
||||
pfx="";
|
||||
}
|
||||
this.mStartPrefix = pfx;
|
||||
}
|
||||
public void setEndPrefix(String pfx) {
|
||||
void setEndPrefix(String pfx) {
|
||||
if(pfx==null){
|
||||
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){
|
||||
mIndentScale=scale;
|
||||
}
|
||||
@ -254,82 +169,11 @@ public class XMLElement {
|
||||
public void setResourceId(int 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) {
|
||||
XMLElement baseElement=new XMLElement(tag);
|
||||
addChildNoCheck(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) {
|
||||
if(elements==null){
|
||||
return;
|
||||
@ -338,8 +182,14 @@ public class XMLElement {
|
||||
addChild(element);
|
||||
}
|
||||
}
|
||||
public void addChild(XMLElement baseElement) {
|
||||
addChildNoCheck(baseElement);
|
||||
public void addChild(XMLElement child) {
|
||||
addChildNoCheck(child);
|
||||
}
|
||||
private void clearChildElements(){
|
||||
mChildes.clear();
|
||||
}
|
||||
private void clearTexts(){
|
||||
mTexts.clear();
|
||||
}
|
||||
public XMLComment getCommentAt(int index){
|
||||
if(mComments==null || index<0){
|
||||
@ -352,7 +202,7 @@ public class XMLElement {
|
||||
}
|
||||
public void hideComments(boolean recursive, boolean hide){
|
||||
hideComments(hide);
|
||||
if(recursive && mChildes!=null){
|
||||
if(recursive){
|
||||
for(XMLElement child:mChildes){
|
||||
child.hideComments(recursive, hide);
|
||||
}
|
||||
@ -397,75 +247,30 @@ public class XMLElement {
|
||||
mComments.add(commentElement);
|
||||
commentElement.setIndent(getIndent());
|
||||
commentElement.setParent(this);
|
||||
super.addChildNode(commentElement);
|
||||
}
|
||||
public void removeAllChildes(){
|
||||
if(mChildes==null){
|
||||
return;
|
||||
}
|
||||
public void removeChildElements(){
|
||||
mChildes.clear();
|
||||
}
|
||||
public int getChildesCount(){
|
||||
if(mChildes==null){
|
||||
return 0;
|
||||
public List<XMLAttribute> listAttributes(){
|
||||
return mAttributes;
|
||||
}
|
||||
public int getChildesCount(){
|
||||
return mChildes.size();
|
||||
}
|
||||
public XMLElement getFirstElementByTagName(String tagName){
|
||||
if(tagName==null||mChildes==null){
|
||||
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 List<XMLElement> listChildElements(){
|
||||
return mChildes;
|
||||
}
|
||||
public XMLElement getChildAt(int index){
|
||||
if(mChildes==null||index<0){
|
||||
return null;
|
||||
}
|
||||
if(index>=mChildes.size()){
|
||||
if(index<0 || index>=mChildes.size()){
|
||||
return null;
|
||||
}
|
||||
return mChildes.get(index);
|
||||
}
|
||||
public int getAttributeCount(){
|
||||
if(mAttributes==null){
|
||||
return 0;
|
||||
}
|
||||
return mAttributes.size();
|
||||
}
|
||||
public XMLAttribute getAttributeAt(int index){
|
||||
if(mAttributes==null||index<0){
|
||||
return null;
|
||||
}
|
||||
if(index>=mAttributes.size()){
|
||||
return null;
|
||||
}
|
||||
@ -514,9 +319,6 @@ public class XMLElement {
|
||||
return attr.getValueBool();
|
||||
}
|
||||
public XMLAttribute getAttribute(String name){
|
||||
if(mAttributes==null){
|
||||
return null;
|
||||
}
|
||||
if(XMLUtil.isEmpty(name)){
|
||||
return null;
|
||||
}
|
||||
@ -585,42 +387,22 @@ public class XMLElement {
|
||||
if(exist!=null){
|
||||
return;
|
||||
}
|
||||
if(mAttributes==null){
|
||||
mAttributes=new ArrayList<>();
|
||||
}
|
||||
mAttributes.add(attr);
|
||||
}
|
||||
private void addAttributeNoCheck(XMLAttribute attr){
|
||||
if(attr==null){
|
||||
if(attr==null || attr.isEmpty()){
|
||||
return;
|
||||
}
|
||||
if(XMLUtil.isEmpty(attr.getName())){
|
||||
return;
|
||||
}
|
||||
if(mAttributes==null){
|
||||
mAttributes=new ArrayList<>();
|
||||
}
|
||||
mAttributes.add(attr);
|
||||
}
|
||||
public void sortChildes(Comparator<XMLElement> comparator){
|
||||
if(mChildes==null||comparator==null){
|
||||
if(comparator==null){
|
||||
return;
|
||||
}
|
||||
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){
|
||||
if(mAttributes==null || comparator==null){
|
||||
if(comparator==null){
|
||||
return;
|
||||
}
|
||||
mAttributes.sort(comparator);
|
||||
@ -631,16 +413,14 @@ public class XMLElement {
|
||||
void setParent(XMLElement baseElement){
|
||||
mParent=baseElement;
|
||||
}
|
||||
private void addChildNoCheck(XMLElement baseElement){
|
||||
if(baseElement==null){
|
||||
private void addChildNoCheck(XMLElement child){
|
||||
if(child==null || child == this){
|
||||
return;
|
||||
}
|
||||
if(mChildes==null){
|
||||
mChildes=new ArrayList<>();
|
||||
}
|
||||
baseElement.setParent(this);
|
||||
baseElement.setIndent(getChildIndent());
|
||||
mChildes.add(baseElement);
|
||||
child.setParent(this);
|
||||
child.setIndent(getChildIndent());
|
||||
mChildes.add(child);
|
||||
super.addChildNode(child);
|
||||
}
|
||||
public int getLevel(){
|
||||
int rs=0;
|
||||
@ -652,10 +432,13 @@ public class XMLElement {
|
||||
return rs;
|
||||
}
|
||||
int getIndent(){
|
||||
if(hasTextContent()){
|
||||
return 0;
|
||||
}
|
||||
return mIndent;
|
||||
}
|
||||
int getChildIndent(){
|
||||
if(mIndent<=0){
|
||||
if(mIndent<=0 || hasTextContent()){
|
||||
return 0;
|
||||
}
|
||||
int rs=mIndent+1;
|
||||
@ -671,11 +454,9 @@ public class XMLElement {
|
||||
}
|
||||
public void setIndent(int indent){
|
||||
mIndent=indent;
|
||||
if(mChildes!=null){
|
||||
int chIndent=getChildIndent();
|
||||
for(XMLElement be:mChildes){
|
||||
be.setIndent(chIndent);
|
||||
}
|
||||
for(XMLElement child:mChildes){
|
||||
child.setIndent(chIndent);
|
||||
}
|
||||
if(mComments!=null){
|
||||
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 {
|
||||
int i=0;
|
||||
String tagName=getTagName();
|
||||
@ -770,18 +535,32 @@ public class XMLElement {
|
||||
mTag =tag;
|
||||
}
|
||||
public String getTextContent(){
|
||||
return getTextContent(false);
|
||||
return getTextContent(true);
|
||||
}
|
||||
public String getTextContent(boolean unEscape){
|
||||
XMLTextAttribute textAttribute= getTextAttr();
|
||||
return textAttribute.getText(unEscape);
|
||||
String text=buildTextContent();
|
||||
if(unEscape){
|
||||
text=XMLUtil.unEscapeXmlChars(text);
|
||||
}
|
||||
public XMLTextAttribute getTextAttribute(){
|
||||
String txt=getTextContent();
|
||||
if(txt==null){
|
||||
return text;
|
||||
}
|
||||
private String buildTextContent(){
|
||||
if(!hasTextContent()){
|
||||
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(){
|
||||
if(mTextAttribute==null){
|
||||
@ -789,43 +568,27 @@ public class XMLElement {
|
||||
}
|
||||
return mTextAttribute;
|
||||
}
|
||||
private boolean appendTextContent(Writer writer) throws IOException {
|
||||
if(mTextAttribute==null){
|
||||
return false;
|
||||
private void appendTextContent(Writer writer) throws IOException {
|
||||
for(XMLNode child:getChildNodes()){
|
||||
if(child instanceof XMLElement){
|
||||
((XMLElement)child).setIndent(0);
|
||||
}
|
||||
return mTextAttribute.write(writer);
|
||||
}
|
||||
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;
|
||||
child.write(writer, false);
|
||||
}
|
||||
}
|
||||
setTextContent(text);
|
||||
public boolean hasTextContent() {
|
||||
return mTexts.size()>0;
|
||||
}
|
||||
public XMLAttribute setTextContent(String text){
|
||||
return setTextContent(text, true);
|
||||
public void setTextContent(String text){
|
||||
setTextContent(text, true);
|
||||
}
|
||||
public XMLAttribute setTextContent(String text, boolean escape){
|
||||
XMLTextAttribute textAttribute= getTextAttr();
|
||||
if(XMLUtil.isEmpty(text)){
|
||||
textAttribute.setText(null);
|
||||
//textAttribute.setText(text);
|
||||
}else {
|
||||
public void setTextContent(String text, boolean escape){
|
||||
clearChildElements();
|
||||
clearTexts();
|
||||
if(escape){
|
||||
text=XMLUtil.escapeXmlChars(text);
|
||||
}
|
||||
textAttribute.setText(text);
|
||||
}
|
||||
return textAttribute;
|
||||
appendText(text);
|
||||
}
|
||||
private boolean appendAttributes(Writer writer, boolean newLineAttributes) throws IOException {
|
||||
if(mAttributes==null){
|
||||
@ -851,50 +614,24 @@ public class XMLElement {
|
||||
}
|
||||
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(){
|
||||
if(mTagName!=null){
|
||||
return false;
|
||||
}
|
||||
if(mAttributes!=null && mAttributes.size()>0){
|
||||
if(mAttributes.size()>0){
|
||||
return false;
|
||||
}
|
||||
if(mComments!=null && mComments.size()>0){
|
||||
return false;
|
||||
}
|
||||
return getTextContent()==null;
|
||||
}
|
||||
private boolean canAppendChildes(){
|
||||
if(mChildes==null){
|
||||
if(mTexts.size()>0){
|
||||
return false;
|
||||
}
|
||||
for(XMLElement be:mChildes){
|
||||
if (!be.isEmpty()){
|
||||
return true;
|
||||
}
|
||||
private boolean canAppendChildes(){
|
||||
for(XMLElement child:mChildes){
|
||||
if (!child.isEmpty()){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -921,22 +658,19 @@ public class XMLElement {
|
||||
return addedOnce;
|
||||
}
|
||||
private boolean appendChildes(Writer writer, boolean newLineAttributes) throws IOException {
|
||||
if(mChildes==null){
|
||||
return false;
|
||||
}
|
||||
boolean appendPrevious=true;
|
||||
boolean addedOnce=false;
|
||||
for(XMLElement be:mChildes){
|
||||
for(XMLElement child:mChildes){
|
||||
if(stopWriting(writer)){
|
||||
break;
|
||||
}
|
||||
if(be.isEmpty()){
|
||||
if(child.isEmpty()){
|
||||
continue;
|
||||
}
|
||||
if(appendPrevious){
|
||||
writer.write(XMLUtil.NEW_LINE);
|
||||
}
|
||||
appendPrevious=be.write(writer, newLineAttributes);
|
||||
appendPrevious=child.write(writer, newLineAttributes);
|
||||
if(!addedOnce && appendPrevious){
|
||||
addedOnce=true;
|
||||
}
|
||||
@ -954,6 +688,7 @@ public class XMLElement {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
public boolean write(Writer writer, boolean newLineAttributes) throws IOException {
|
||||
if(isEmpty()){
|
||||
return false;
|
||||
@ -973,20 +708,15 @@ public class XMLElement {
|
||||
}
|
||||
appendAttributes(writer, newLineAttributes);
|
||||
boolean useEndTag=false;
|
||||
if(canAppendChildes()){
|
||||
writer.write(mEnd);
|
||||
appendChildes(writer, newLineAttributes);
|
||||
useEndTag=true;
|
||||
}
|
||||
boolean hasTextCon=hasTextContent();
|
||||
if(hasTextCon){
|
||||
if(!useEndTag){
|
||||
writer.write(mEnd);
|
||||
}else {
|
||||
writer.write(XMLUtil.NEW_LINE);
|
||||
}
|
||||
appendTextContent(writer);
|
||||
useEndTag=true;
|
||||
}else if(canAppendChildes()){
|
||||
writer.write(mEnd);
|
||||
appendChildes(writer, newLineAttributes);
|
||||
useEndTag=true;
|
||||
}
|
||||
if(useEndTag){
|
||||
if(!hasTextCon){
|
||||
@ -996,19 +726,13 @@ public class XMLElement {
|
||||
writer.write(mStart);
|
||||
writer.write(mStartPrefix);
|
||||
writer.write(getTagName());
|
||||
writer.write(mEnd);
|
||||
}else {
|
||||
writer.write(mEndPrefix);
|
||||
writer.write(mEnd);
|
||||
}
|
||||
writer.write(mEnd);
|
||||
return true;
|
||||
}
|
||||
public String toText(){
|
||||
return toText(1, false);
|
||||
}
|
||||
public String toText(boolean newLineAttributes){
|
||||
return toText(1, newLineAttributes);
|
||||
}
|
||||
@Override
|
||||
public String toText(int indent, boolean newLineAttributes){
|
||||
StringWriter writer=new StringWriter();
|
||||
setIndent(indent);
|
||||
@ -1020,6 +744,24 @@ public class XMLElement {
|
||||
}
|
||||
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
|
||||
public String toString(){
|
||||
StringWriter strWriter=new StringWriter();
|
||||
@ -1032,23 +774,4 @@ public class XMLElement {
|
||||
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();
|
||||
setDefaultAttr();
|
||||
}
|
||||
@Override
|
||||
XMLElement onCloneElement(){
|
||||
return new XmlHeaderElement(this);
|
||||
}
|
||||
@Override
|
||||
void cloneAllAttributes(XMLElement element){
|
||||
}
|
||||
private void copyAll(XmlHeaderElement element){
|
||||
if(element==null){
|
||||
return;
|
||||
|
@ -260,10 +260,10 @@ public class XMLDocumentParser {
|
||||
}
|
||||
String text=mCurrentText.toString();
|
||||
mCurrentText=null;
|
||||
if(XMLUtil.isEmpty(text)){
|
||||
if(text.trim().length()==0 && !mCurrentElement.hasTextContent()){
|
||||
return;
|
||||
}
|
||||
mCurrentElement.setTextContent(text, true);
|
||||
mCurrentElement.addText(new XMLText(text));
|
||||
}
|
||||
private void onEntityRef(){
|
||||
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