001package arcommon.xml;
002
003import java.io.ByteArrayInputStream;
004import java.io.File;
005import java.io.InputStream;
006import java.io.Serializable;
007import java.io.StringReader;
008import java.io.UnsupportedEncodingException;
009
010import javax.xml.parsers.DocumentBuilder;
011import javax.xml.parsers.DocumentBuilderFactory;
012import javax.xml.parsers.SAXParser;
013import javax.xml.parsers.SAXParserFactory;
014import javax.xml.xpath.XPath;
015import javax.xml.xpath.XPathConstants;
016import javax.xml.xpath.XPathExpression;
017import javax.xml.xpath.XPathExpressionException;
018import javax.xml.xpath.XPathFactory;
019
020import org.w3c.dom.Document;
021import org.w3c.dom.NamedNodeMap;
022import org.w3c.dom.Node;
023import org.w3c.dom.NodeList;
024import org.xml.sax.Attributes;
025import org.xml.sax.InputSource;
026import org.xml.sax.helpers.DefaultHandler;
027
028import arcommon.FileUtil;
029
030public class XmlUtil {
031    public static final String XML_ENCODING = "UTF-8";
032    
033    public static Document stringToDocument(String xml) {
034        try {
035            DocumentBuilder db = DocumentBuilderFactory.newInstance().newDocumentBuilder();
036            InputSource is = new InputSource();
037            is.setCharacterStream(new StringReader(xml));
038            Document doc = db.parse(is);
039            return doc;
040        } catch (Exception e) {
041            throw new RuntimeException(e);
042        }
043    }
044    
045    public static XPathExpression createXPathExpression(String xpathString) {
046        XPathFactory xPathFactory = XPathFactory.newInstance();
047        XPath xpath = xPathFactory.newXPath();
048        try {
049            XPathExpression xPathExpression = xpath.compile(xpathString);
050            return xPathExpression;
051        } catch (XPathExpressionException e) {
052            throw new RuntimeException(e);
053        }
054    }
055    
056    public static NodeList selectNodes(String xml, String xpathString) {
057        Document doc = stringToDocument(xml);
058        XPathExpression xPathExpression = createXPathExpression(xpathString);
059        return selectNodes(doc, xPathExpression);
060    }
061    
062    public static NodeList selectNodes(Document doc, String xpathString) {
063        XPathExpression xPathExpression = createXPathExpression(xpathString);
064        return selectNodes(doc, xPathExpression);
065    }
066    
067    public static NodeList selectNodes(Document doc, XPathExpression xPathExpression) {
068        try {
069            NodeList nodes = ((NodeList) xPathExpression.evaluate(doc, XPathConstants.NODESET));
070            return nodes;
071        } catch (XPathExpressionException e) {
072            throw new RuntimeException(e);
073        }
074    }
075    
076    public static void printNode(Node node) {
077        printNode(node, "");
078    }
079    
080    private static void printNode(Node node, String indent) {
081        if (node.getLocalName() != null) {
082            System.out.println("node.getLocalName(): " + node.getLocalName());
083        }
084        System.out.print(indent + "<");
085        if (node.getNamespaceURI() != null) {
086            System.out.print(node.getNamespaceURI() + ":");
087        }
088        System.out.print(node.getNodeName() + " ");
089        NamedNodeMap attributes = node.getAttributes();
090        if (attributes != null) {
091            for (int i = 0; i < attributes.getLength(); i++) {
092                Node item = attributes.item(i);
093                System.out.print(item.getNodeName() + "=\"" + item.getNodeValue() + "\" ");
094            }
095        }
096        if (node.getNodeValue() != null && node.getNodeValue().length() > 0) {
097            System.out.print("node.getNodeValue()=\"" + encodeWhiteSpace(node.getNodeValue()) + "\" ");
098        }
099        if (node.getTextContent() != null && node.getTextContent().length() > 0 && !node.getTextContent().equals(node.getNodeValue())) {
100            System.out.print("node.getTextContent()=\"" + encodeWhiteSpace(node.getTextContent()) + "\" ");
101        }
102        NodeList childNodes = node.getChildNodes();
103        if (childNodes != null && childNodes.getLength() > 0) {
104            System.out.println(">");
105            
106            for (int i = 0; i < childNodes.getLength(); i++) {
107                printNode(childNodes.item(i), indent + "  ");
108            }
109            
110            System.out.println(indent + "</" + node.getNodeName() + ">");
111        } else {
112            System.out.println("/>");
113        }
114    }
115    
116    private static String encodeWhiteSpace(String string) {
117        string = string.replace("\r", "\\r");
118        string = string.replace("\n", "\\n");
119        string = string.replace("\t", "\\t");
120        return string;
121    }
122    
123    // Note: Doesn't read file encoding from XML
124    public static void saxParseFile(String fileName, DefaultHandler handler) {
125        try {
126            SAXParser saxParser = getSAXParser();
127            saxParser.parse(new File(fileName), handler);
128        } catch (RuntimeException e) {
129            throw e;
130        } catch (Exception e) {
131            throw new RuntimeException(e);
132        }
133    }
134
135    // Doesn't work. Something is wrong with encoding
136/*    public static void saxParseFileEncodingFromXml(String fileName, DefaultHandler handler) {
137        try {
138            File file = new File(fileName);
139            FileInputStream fileInputStream = new FileInputStream(file);
140            
141            Reader inputStreamReader = new InputStreamReader(fileInputStream);
142            InputSource is = new InputSource();
143            is.setCharacterStream(inputStreamReader);
144            
145            saxParseInputSource(is, handler);
146        } catch (Exception e) {
147            System.out.println("XmlUtil.saxParseFile(): fileName: " + fileName);
148            throw new RuntimeException(e);
149        }
150    }*/
151    
152    public static void saxParseXml(String xml, DefaultHandler handler) {
153        InputStream stream;
154        try {
155            stream = new ByteArrayInputStream(xml.getBytes(XML_ENCODING));
156        } catch (UnsupportedEncodingException e) {
157            throw new RuntimeException(e);
158        }
159        InputSource is = new InputSource();
160        is.setByteStream(stream);
161        saxParseInputSource(is, handler);
162    }
163    
164    public static SAXParser getSAXParser() {
165        try {
166            SAXParserFactory factory = SAXParserFactory.newInstance();
167            SAXParser saxParser = factory.newSAXParser();
168            return saxParser;
169        } catch (RuntimeException e) {
170            throw e;
171        } catch (Exception e) {
172            throw new RuntimeException(e);
173        }
174    }
175    
176    public static void saxParseInputSource(InputSource is, DefaultHandler handler) {
177        try {
178            SAXParser saxParser = getSAXParser();
179            saxParser.parse(is, handler);
180        } catch (RuntimeException e) {
181            throw e;
182        } catch (Exception e) {
183            throw new RuntimeException(e);
184        }
185    }
186    
187    public static void objectToXmlFile(String fileName, Serializable object) {
188        String xml = objectToXmlString(object);
189        FileUtil.writeFile(fileName, xml, false, XML_ENCODING);
190    }
191    
192    public static String objectToXmlString(Serializable object) {
193        XmlSerializer xmlSerializer = new XmlSerializer();
194        String xml = xmlSerializer.objectToXmlString(object);
195        return xml;
196    }
197    
198    public static Serializable xmlFileToObject(String fileName) {
199        XmlDeserializer xmlDeserializer = new XmlDeserializer();
200        XmlUtil.saxParseFile(fileName, xmlDeserializer);
201        return xmlDeserializer.getResultObject();
202    }
203    
204    public static Serializable xmlStringToObject(String xml) {
205        XmlDeserializer xmlDeserializer = new XmlDeserializer();
206        XmlUtil.saxParseXml(xml, xmlDeserializer);
207        return xmlDeserializer.getResultObject();
208    }
209    
210    public static String attributesToString(Attributes attributes) {
211        String result = "";
212        for (int i = 0; i < attributes.getLength(); i++) {
213            if (result.length() > 0) {
214                result += " ";
215            }
216            result += attributes.getQName(i) + "=\"" + attributes.getValue(i) + "\"";
217        }
218        return result;
219    }
220    
221    /**
222     * Encodes the string parameter in XML encoding (&name;).
223     * @see #decodeXmlString(String)
224     * @see arcommon.net.NetUtil#encodeUrlMyVariant(String)
225     * @see arcommon.net.NetUtil#decodeUrlToDisplayString(String)
226     */
227    public static String encodeXmlString(String string) {
228        if (string == null) {
229            return null;
230        }
231        
232        string = string.replace("&", "&amp;");
233        string = string.replace("<", "&lt;");
234        string = string.replace(">", "&gt;");
235        string = string.replace("\"", "&quot;");
236        string = string.replace("'", "&apos;");
237        
238        return string;
239    }
240    
241    /**
242     * Decodes the string parameter from XML encoding (&name;).
243     * @see #encodeXmlString(String)
244     * @see arcommon.net.NetUtil#encodeUrlMyVariant(String)
245     * @see arcommon.net.NetUtil#decodeUrlToDisplayString(String)
246     */
247    public static String decodeXmlString(String string) {
248        if (string == null) {
249            return null;
250        }
251        
252        string = string.replace("&lt;", "<");
253        string = string.replace("&gt;", ">");
254        string = string.replace("&quot;", "\"");
255        string = string.replace("&apos;", "'");
256        string = string.replace("&amp;", "&");
257        
258        return string;
259    }
260}