package com.wj.dexknife.shell.apkparser.parser; import com.wj.dexknife.shell.apkparser.struct.xml.Attribute; import com.wj.dexknife.shell.apkparser.struct.xml.XmlCData; import com.wj.dexknife.shell.apkparser.struct.xml.XmlNamespaceEndTag; import com.wj.dexknife.shell.apkparser.struct.xml.XmlNamespaceStartTag; import com.wj.dexknife.shell.apkparser.struct.xml.XmlNodeEndTag; import com.wj.dexknife.shell.apkparser.struct.xml.XmlNodeStartTag; import com.wj.dexknife.shell.apkparser.utils.xml.XmlEscaper; import java.util.List; /** * trans to xml text when parse binary xml file. * * @author dongliu */ public class XmlTranslator implements XmlStreamer { private StringBuilder sb; private int shift = 0; private XmlNamespaces namespaces; private boolean isLastStartTag; public XmlTranslator() { sb = new StringBuilder(); sb.append("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"); this.namespaces = new XmlNamespaces(); } @Override public void onStartTag(XmlNodeStartTag xmlNodeStartTag) { if (isLastStartTag) { sb.append(">\n"); } appendShift(shift++); sb.append('<'); if (xmlNodeStartTag.getNamespace() != null) { String prefix = namespaces.getPrefixViaUri(xmlNodeStartTag.getNamespace()); if (prefix != null) { sb.append(prefix).append(":"); } else { sb.append(xmlNodeStartTag.getNamespace()).append(":"); } } sb.append(xmlNodeStartTag.getName()); List<XmlNamespaces.XmlNamespace> nps = namespaces.consumeNameSpaces(); if (!nps.isEmpty()) { for (XmlNamespaces.XmlNamespace np : nps) { sb.append(" xmlns:").append(np.getPrefix()).append("=\"") .append(np.getUri()) .append("\""); } } isLastStartTag = true; for (Attribute attribute : xmlNodeStartTag.getAttributes().value()) { onAttribute(attribute); } } private void onAttribute(Attribute attribute) { sb.append(" "); String namespace = this.namespaces.getPrefixViaUri(attribute.getNamespace()); if (namespace == null) { namespace = attribute.getNamespace(); } if (namespace != null && !namespace.isEmpty()) { sb.append(namespace).append(':'); } String escapedFinalValue = XmlEscaper.escapeXml10(attribute.getValue()); sb.append(attribute.getName()).append('=').append('"') .append(escapedFinalValue).append('"'); } @Override public void onEndTag(XmlNodeEndTag xmlNodeEndTag) { --shift; if (isLastStartTag) { sb.append(" />\n"); } else { appendShift(shift); sb.append("</"); if (xmlNodeEndTag.getNamespace() != null) { sb.append(xmlNodeEndTag.getNamespace()).append(":"); } sb.append(xmlNodeEndTag.getName()); sb.append(">\n"); } isLastStartTag = false; } @Override public void onCData(XmlCData xmlCData) { appendShift(shift); sb.append(xmlCData.getValue()).append('\n'); isLastStartTag = false; } @Override public void onNamespaceStart(XmlNamespaceStartTag tag) { this.namespaces.addNamespace(tag); } @Override public void onNamespaceEnd(XmlNamespaceEndTag tag) { this.namespaces.removeNamespace(tag); } private void appendShift(int shift) { for (int i = 0; i < shift; i++) { sb.append("\t"); } } public String getXml() { return sb.toString(); } }