1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.mybatis.generator.internal;
17
18 import static org.mybatis.generator.internal.util.messages.Messages.getString;
19
20 import java.io.File;
21 import java.io.FileInputStream;
22 import java.io.IOException;
23 import java.io.InputStreamReader;
24 import java.io.StringReader;
25 import java.util.ArrayList;
26 import java.util.List;
27
28 import javax.xml.parsers.DocumentBuilder;
29 import javax.xml.parsers.DocumentBuilderFactory;
30 import javax.xml.parsers.ParserConfigurationException;
31
32 import org.mybatis.generator.api.GeneratedXmlFile;
33 import org.mybatis.generator.config.MergeConstants;
34 import org.mybatis.generator.exception.ShellException;
35 import org.w3c.dom.Comment;
36 import org.w3c.dom.Document;
37 import org.w3c.dom.DocumentType;
38 import org.w3c.dom.Element;
39 import org.w3c.dom.NamedNodeMap;
40 import org.w3c.dom.Node;
41 import org.w3c.dom.NodeList;
42 import org.w3c.dom.Text;
43 import org.xml.sax.EntityResolver;
44 import org.xml.sax.InputSource;
45 import org.xml.sax.SAXException;
46
47
48
49
50
51
52 public class XmlFileMergerJaxp {
53 private static class NullEntityResolver implements EntityResolver {
54
55
56
57
58
59 public InputSource resolveEntity(String publicId, String systemId)
60 throws SAXException, IOException {
61
62 StringReader sr = new StringReader("");
63
64 return new InputSource(sr);
65 }
66 }
67
68
69
70
71 private XmlFileMergerJaxp() {
72 super();
73 }
74
75 public static String getMergedSource(GeneratedXmlFile generatedXmlFile,
76 File existingFile) throws ShellException {
77
78 try {
79 return getMergedSource(new InputSource(new StringReader(generatedXmlFile.getFormattedContent())),
80 new InputSource(new InputStreamReader(new FileInputStream(existingFile), "UTF-8")),
81 existingFile.getName());
82 } catch (IOException e) {
83 throw new ShellException(getString("Warning.13",
84 existingFile.getName()), e);
85 } catch (SAXException e) {
86 throw new ShellException(getString("Warning.13",
87 existingFile.getName()), e);
88 } catch (ParserConfigurationException e) {
89 throw new ShellException(getString("Warning.13",
90 existingFile.getName()), e);
91 }
92 }
93
94 public static String getMergedSource(InputSource newFile,
95 InputSource existingFile, String existingFileName) throws IOException, SAXException,
96 ParserConfigurationException, ShellException {
97
98 DocumentBuilderFactory factory = DocumentBuilderFactory
99 .newInstance();
100 factory.setExpandEntityReferences(false);
101 DocumentBuilder builder = factory.newDocumentBuilder();
102 builder.setEntityResolver(new NullEntityResolver());
103
104 Document existingDocument = builder.parse(existingFile);
105 Document newDocument = builder.parse(newFile);
106
107 DocumentType newDocType = newDocument.getDoctype();
108 DocumentType existingDocType = existingDocument.getDoctype();
109
110 if (!newDocType.getName().equals(existingDocType.getName())) {
111 throw new ShellException(getString("Warning.12",
112 existingFileName));
113 }
114
115 Element existingRootElement = existingDocument.getDocumentElement();
116 Element newRootElement = newDocument.getDocumentElement();
117
118
119
120
121
122
123 NamedNodeMap attributes = existingRootElement.getAttributes();
124 int attributeCount = attributes.getLength();
125 for (int i = attributeCount - 1; i >= 0; i--) {
126 Node node = attributes.item(i);
127 existingRootElement.removeAttribute(node.getNodeName());
128 }
129
130
131 attributes = newRootElement.getAttributes();
132 attributeCount = attributes.getLength();
133 for (int i = 0; i < attributeCount; i++) {
134 Node node = attributes.item(i);
135 existingRootElement.setAttribute(node.getNodeName(), node
136 .getNodeValue());
137 }
138
139
140
141 List<Node> nodesToDelete = new ArrayList<Node>();
142 NodeList children = existingRootElement.getChildNodes();
143 int length = children.getLength();
144 for (int i = 0; i < length; i++) {
145 Node node = children.item(i);
146 if (isGeneratedNode(node)) {
147 nodesToDelete.add(node);
148 } else if (isWhiteSpace(node)
149 && isGeneratedNode(children.item(i + 1))) {
150 nodesToDelete.add(node);
151 }
152 }
153
154 for (Node node : nodesToDelete) {
155 existingRootElement.removeChild(node);
156 }
157
158
159 children = newRootElement.getChildNodes();
160 length = children.getLength();
161 Node firstChild = existingRootElement.getFirstChild();
162 for (int i = 0; i < length; i++) {
163 Node node = children.item(i);
164
165 if (i == length - 1 && isWhiteSpace(node)) {
166 break;
167 }
168
169 Node newNode = existingDocument.importNode(node, true);
170 if (firstChild == null) {
171 existingRootElement.appendChild(newNode);
172 } else {
173 existingRootElement.insertBefore(newNode, firstChild);
174 }
175 }
176
177
178 return prettyPrint(existingDocument);
179 }
180
181 private static String prettyPrint(Document document) throws ShellException {
182 DomWriter dw = new DomWriter();
183 String s = dw.toString(document);
184 return s;
185 }
186
187 private static boolean isGeneratedNode(Node node) {
188 boolean rc = false;
189
190 if (node != null && node.getNodeType() == Node.ELEMENT_NODE) {
191 Element element = (Element) node;
192 String id = element.getAttribute("id");
193 if (id != null) {
194 for (String prefix : MergeConstants.OLD_XML_ELEMENT_PREFIXES) {
195 if (id.startsWith(prefix)) {
196 rc = true;
197 break;
198 }
199 }
200 }
201
202 if (rc == false) {
203
204
205
206
207 NodeList children = node.getChildNodes();
208 int length = children.getLength();
209 for (int i = 0; i < length; i++) {
210 Node childNode = children.item(i);
211 if (isWhiteSpace(childNode)) {
212 continue;
213 } else if (childNode.getNodeType() == Node.COMMENT_NODE) {
214 Comment comment = (Comment) childNode;
215 String commentData = comment.getData();
216 for (String tag : MergeConstants.OLD_ELEMENT_TAGS) {
217 if (commentData.contains(tag)) {
218 rc = true;
219 break;
220 }
221 }
222 } else {
223 break;
224 }
225 }
226 }
227 }
228
229 return rc;
230 }
231
232 private static boolean isWhiteSpace(Node node) {
233 boolean rc = false;
234
235 if (node != null && node.getNodeType() == Node.TEXT_NODE) {
236 Text tn = (Text) node;
237 if (tn.getData().trim().length() == 0) {
238 rc = true;
239 }
240 }
241
242 return rc;
243 }
244 }