Java实现无XSLT的XML属性转标签及通用XML合并方案
Alright, let's break this down. You need two key tasks done in pure Java (no XSLT): converting XML attributes to elements, and merging two XML files where one has a full element structure and the other stores corresponding data as attributes. Plus, you want this to work generically for multiple XML pairs. Here's a complete, reusable solution using Java's built-in DOM API—no external libraries needed:
First, let's define the sample inputs you referenced to ground the solution:
Sample Inputs
Element-Structured XML (Input 1)
<PROPERTIES> <PROPERTY> <ADDRESS> <AddressLineText></AddressLineText> <CityName>New York</CityName> <PostalCode>10001</PostalCode> </ADDRESS> </PROPERTY> </PROPERTIES>
Attribute-Based XML (Input 2)
<PROPERTIES> <PROPERTY AddressLineText="123 Main St" CityName="New York" PostalCode="10001"/> </PROPERTIES>
1. Attribute-to-Element Conversion
This recursive method will scan every node in your XML and turn all attributes into child elements. It works for nested structures too.
Reusable Utility Class
import org.w3c.dom.*; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import java.io.File; import java.io.StringWriter; public class XmlProcessor { // Convert all attributes in a node (and its children) to child elements public static void attributesToElements(Node node) { if (node.getNodeType() == Node.ELEMENT_NODE) { Element element = (Element) node; // Process attributes in reverse order to avoid index shifting issues NamedNodeMap attributes = element.getAttributes(); for (int i = attributes.getLength() - 1; i >= 0; i--) { Attr attr = (Attr) attributes.item(i); // Create a new element with the attribute's name Element attrElement = element.getOwnerDocument().createElement(attr.getName()); attrElement.setTextContent(attr.getValue()); // Add the new element as a child, then remove the original attribute element.appendChild(attrElement); element.removeAttributeNode(attr); } // Recurse through all child nodes NodeList children = element.getChildNodes(); for (int i = 0; i < children.getLength(); i++) { attributesToElements(children.item(i)); } } } // Helper: Load XML from a file public static Document loadXml(File file) throws Exception { return DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(file); } // Helper: Save XML document to a file public static void saveXml(Document doc, File output) throws Exception { Transformer transformer = TransformerFactory.newInstance().newTransformer(); transformer.setOutputProperty(javax.xml.transform.OutputKeys.INDENT, "yes"); transformer.transform(new DOMSource(doc), new StreamResult(output)); } // Helper: Convert document to a formatted string for debugging public static String docToString(Document doc) throws Exception { StringWriter writer = new StringWriter(); Transformer transformer = TransformerFactory.newInstance().newTransformer(); transformer.setOutputProperty(javax.xml.transform.OutputKeys.INDENT, "yes"); transformer.transform(new DOMSource(doc), new StreamResult(writer)); return writer.toString(); } }
How to Use It
public class AttributeConversionDemo { public static void main(String[] args) throws Exception { File input = new File("path/to/attribute-based.xml"); File output = new File("path/to/converted-element.xml"); Document doc = XmlProcessor.loadXml(input); XmlProcessor.attributesToElements(doc.getDocumentElement()); XmlProcessor.saveXml(doc, output); System.out.println("Converted XML:\n" + XmlProcessor.docToString(doc)); } }
2. Merging Element-Structured and Attribute-Based XMLs
This method will match nodes by tag name (you can extend this to use unique IDs if needed) and fill the empty elements in your structure XML with values from the attribute-based XML.
Add This Method to XmlProcessor
// Merge attribute-based data into the element-structured XML public static void mergeXml(Document structureDoc, Document attributeDoc) { Element structureRoot = structureDoc.getDocumentElement(); Element attributeRoot = attributeDoc.getDocumentElement(); // Start merging from the root nodes mergeMatchingNodes(structureRoot, attributeRoot); } private static void mergeMatchingNodes(Element structureNode, Element attributeNode) { // Skip if node tags don't match if (!structureNode.getTagName().equals(attributeNode.getTagName())) { return; } // Fill structure elements with attribute values NamedNodeMap attributes = attributeNode.getAttributes(); for (int i = 0; i < attributes.getLength(); i++) { Attr attr = (Attr) attributes.item(i); // Find the corresponding element in the structure XML Element targetElement = (Element) structureNode.getElementsByTagName(attr.getName()).item(0); if (targetElement != null) { targetElement.setTextContent(attr.getValue()); } } // Recurse through child nodes to merge nested data NodeList structureChildren = structureNode.getChildNodes(); NodeList attributeChildren = attributeNode.getChildNodes(); for (int i = 0; i < structureChildren.getLength(); i++) { Node structChild = structureChildren.item(i); if (structChild.getNodeType() == Node.ELEMENT_NODE) { // Find the matching child in the attribute XML for (int j = 0; j < attributeChildren.getLength(); j++) { Node attrChild = attributeChildren.item(j); if (attrChild.getNodeType() == Node.ELEMENT_NODE && attrChild.getTagName().equals(structChild.getTagName())) { mergeMatchingNodes((Element) structChild, (Element) attrChild); break; } } } } }
How to Use the Merge
public class XmlMergeDemo { public static void main(String[] args) throws Exception { File structureFile = new File("path/to/element-structure.xml"); File attributeFile = new File("path/to/attribute-data.xml"); File mergedOutput = new File("path/to/merged-result.xml"); Document structureDoc = XmlProcessor.loadXml(structureFile); Document attributeDoc = XmlProcessor.loadXml(attributeFile); XmlProcessor.mergeXml(structureDoc, attributeDoc); XmlProcessor.saveXml(structureDoc, mergedOutput); System.out.println("Merged XML:\n" + XmlProcessor.docToString(structureDoc)); } }
Sample Merged Output
<PROPERTIES> <PROPERTY> <ADDRESS> <AddressLineText>123 Main St</AddressLineText> <CityName>New York</CityName> <PostalCode>10001</PostalCode> </ADDRESS> </PROPERTY> </PROPERTIES>
Customization Tips
- Matching Logic: If your XML uses unique identifiers (like
idattributes), modifymergeMatchingNodesto match using those instead of tag names for better accuracy. - Large Files: For very large XMLs, swap DOM for SAX to avoid loading the entire document into memory.
- Error Handling: Add checks for missing elements/attributes or validation logic to fit your specific use case.
内容的提问来源于stack exchange,提问作者adbdkb

