/** * Process an MXMLTagData - this will write a String representation of the tag into the * StringWriter passed in. This will strip out any databinding expressions from the String, TODO: * databinding - add the databinding expressions as children of the MXMLXMLNode, and also record * what the TODO: target expressions for those are (these are the expressions to set the value in * the XML object when the TODO: PropertyChange event fires). */ void processNode(MXMLTagData tag, StringWriter sw) { sw.write('<'); if (tag.isCloseTag()) sw.write('/'); sw.write(tag.getName()); String tagPrefix = tag.getPrefix(); // lookup the prefix in case it's defined elsewhere in the document outside the XML tag if (tagPrefix != null) lookupPrefix(tagPrefix, tag); List<MXMLTagAttributeData> attrs = getAttributes(tag); for (MXMLTagAttributeData attr : attrs) { sw.write(' '); sw.write(attr.getName()); sw.write('='); sw.write('"'); sw.write(attr.getRawValue()); sw.write('"'); // lookup the prefix in case it's defined outside the XML tag String prefix = attr.getPrefix(); if (prefix != null) lookupPrefix(prefix, tag); } StringWriter childrenSW = new StringWriter(); for (MXMLUnitData unit = tag.getFirstChildUnit(); unit != null; unit = unit.getNextSiblingUnit()) { processNode(unit, childrenSW); } if (tag == rootTag) { // If we're the root tag, then add an xmlns for each prefix that was referenced by one of our // children, but was defined elsewhere in the document (like in the Application tag). for (String prefix : referencedPrefixes) { String uri = externalPrefixes.getNamespaceForPrefix(prefix); if (uri != null) { sw.write(" xmlns:"); sw.write(prefix); sw.write("=\""); sw.write(uri); sw.write('\"'); } } } if (tag.isEmptyTag()) { sw.write("/>"); } else { sw.write('>'); } sw.write(childrenSW.toString()); MXMLTagData endTag = tag.findMatchingEndTag(); if (endTag != null) { processNode(endTag, sw); } }
/** * Helper to determine if a give MXMLUnitData is the only Text child of an MXMLTagData This * implies special, different processing from normal Text Datas. */ private boolean isOnlyTextChild(MXMLUnitData child) { if (child instanceof MXMLTextData && ((MXMLTextData) child).getTextType() == IMXMLTextData.TextType.TEXT) { MXMLUnitData p = child.getParentUnitData(); MXMLTagData parent = p instanceof MXMLTagData ? (MXMLTagData) p : null; if (parent != null) { return parent.getFirstChildUnit() == child && child.getNextSiblingUnit() == null; } } return false; }
/** * Get the index of a text data. Grabs the parent, and iterates it's children to find out what the * index of the text data passed in should be */ private int getIndexOfText(MXMLTextData text) { MXMLUnitData parent = text.getParentUnitData(); MXMLTagData parentTag = parent instanceof MXMLTagData ? (MXMLTagData) parent : null; int index = 0; if (parentTag != null) { for (MXMLUnitData d = parentTag.getFirstChildUnit(); d != null; d = d.getNextSiblingUnit()) { if (d == text) break; else if (d instanceof MXMLTextData && ((MXMLTextData) d).getTextType() == IMXMLTextData.TextType.CDATA) ++index; } } return index; }
/** * Generate the instructions to set the target expression based on the Data and Attribute passed * in. This will walk up the parent chain to the root tag, and then proceed to emit get * instructions for all parents from the root tag down. For the actual target, instructions to set * the value will be generated. If an attribute is passed in then the set instructions will target * the attribute instead * * @param data The UnitData to target * @param attr The attribute to target, or null if there is no attribute * @return An InstructionList that contains the instructions to set the target expression */ private InstructionList getTargetInstructions(MXMLUnitData data, MXMLTagAttributeData attr) { MXMLUnitData d = data; Stack<MXMLUnitData> parentStack = new Stack<MXMLUnitData>(); if (isOnlyTextChild(d)) { // If we are the only text child of a TagData, then start with the TagData, // as that is what we'll be setting d = d.getParentUnitData(); } MXMLUnitData target = d; // push parents onto a stack, so we can walk down from the parent later while (d != null) { parentStack.add(d); d = d == rootTag ? null : d.getParentUnitData(); } InstructionList il = new InstructionList(); // we're always going to start with "this" il.addInstruction(ABCConstants.OP_getlocal0); // Walk down the parent stack, and emit get instructions for each tag // except for the last one, which is the one we're targeting while (parentStack.size() > 1) { MXMLUnitData unitData = parentStack.pop(); if (unitData instanceof MXMLTagData) { generateGetInstructions(il, (MXMLTagData) unitData); } } if (target instanceof MXMLTagData) { // Targeting a Tag if (attr == null) { // Just setting the tag value generateSetInstructions(il, (MXMLTagData) target); } else { // We have an attr, do a get for the tag, and a set // for the attr generateGetInstructions(il, (MXMLTagData) target); generateSetInstructions(il, attr); } } else if (target instanceof MXMLTextData) { // We're targeting a TextData generateSetInstructions(il, (MXMLTextData) target); } return il; }