1   /**
2    * Copyright (c) 2000-2010 Liferay, Inc. All rights reserved.
3    *
4    * This library is free software; you can redistribute it and/or modify it under
5    * the terms of the GNU Lesser General Public License as published by the Free
6    * Software Foundation; either version 2.1 of the License, or (at your option)
7    * any later version.
8    *
9    * This library is distributed in the hope that it will be useful, but WITHOUT
10   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11   * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
12   * details.
13   */
14  
15  package com.liferay.portal.kernel.xml.simple;
16  
17  import com.liferay.portal.kernel.util.HtmlUtil;
18  import com.liferay.portal.kernel.util.StringBundler;
19  import com.liferay.portal.kernel.util.StringPool;
20  
21  import java.util.LinkedList;
22  
23  /**
24   * <a href="Element.java.html"><b><i>View Source</i></b></a>
25   *
26   * @author Shuyang Zhou
27   * @author Brian Wing Shun Chan
28   */
29  public class Element {
30  
31      public Element(Element parentElement, String name) {
32          this(parentElement, name, null);
33      }
34  
35      public Element(Element parentElement, String name, String text) {
36          if (parentElement._elementClosed) {
37              throw new IllegalArgumentException("Parent element is closed");
38          }
39  
40          _parentElement = parentElement;
41          _name = name;
42          _text = _formatText(text);
43          _elementStack = parentElement._elementStack;
44          _stringBundler = parentElement._stringBundler;
45  
46          _appendChildElement();
47      }
48  
49      public Element(String name) {
50          this(name, null, true);
51      }
52  
53      public Element(String name, boolean addHeader) {
54          this(name, null, addHeader);
55      }
56  
57      public Element(String name, String text) {
58          this(name, text, true);
59      }
60  
61      public Element(String name, String text, boolean addHeader) {
62          _name = name;
63          _text = _formatText(text);
64          _elementStack = new LinkedList<Element>();
65          _stringBundler = new StringBundler();
66  
67          if (addHeader) {
68              _stringBundler.append(_XML_HEADER);
69          }
70  
71          _openElement(this);
72      }
73  
74      public void addAttribute(String name, String value) {
75          if (_openTagClosed) {
76              throw new IllegalStateException("Element is closed");
77          }
78  
79          _stringBundler.append(StringPool.SPACE);
80          _stringBundler.append(name);
81          _stringBundler.append(_EQUAL_QUOTE);
82          _stringBundler.append(value);
83          _stringBundler.append(StringPool.QUOTE);
84      }
85  
86      public Element addElement(String name) {
87          return addElement(name, null);
88      }
89  
90      public Element addElement(String name, boolean text) {
91          return addElement(name, String.valueOf(text));
92      }
93  
94      public Element addElement(String name, double text) {
95          return addElement(name, String.valueOf(text));
96      }
97  
98      public Element addElement(String name, float text) {
99          return addElement(name, String.valueOf(text));
100     }
101 
102     public Element addElement(String name, int text) {
103         return addElement(name, String.valueOf(text));
104     }
105 
106     public Element addElement(String name, long text) {
107         return addElement(name, String.valueOf(text));
108     }
109 
110     public Element addElement(String name, Object text) {
111         return addElement(name, String.valueOf(text));
112     }
113 
114     public Element addElement(String name, short text) {
115         return addElement(name, String.valueOf(text));
116     }
117 
118     public Element addElement(String name, String text) {
119         return new Element(this, name, text);
120     }
121 
122     public String getName() {
123         return _name;
124     }
125 
126     public Element getParentElement() {
127         return _parentElement;
128     }
129 
130     public String getText() {
131         return _text;
132     }
133 
134     public boolean isRootElement() {
135         if (_parentElement == null) {
136             return true;
137         }
138         else {
139             return false;
140         }
141     }
142 
143     public String toXMLString() {
144         if (_parentElement != null) {
145             throw new IllegalStateException(
146                 "XML string can only generated from a root element");
147         }
148 
149         if (_xmlString == null) {
150             _flushPendingOpenElements();
151 
152             _xmlString = _stringBundler.toString();
153         }
154 
155         return _xmlString;
156     }
157 
158     private void _appendChildElement() {
159         Element topElement = _elementStack.getLast();
160 
161         while ((topElement != _parentElement) && (topElement != null)) {
162 
163             // Close previous sibling elements
164 
165             _closeElement(topElement);
166 
167             _elementStack.removeLast();
168 
169             topElement = _elementStack.getLast();
170         }
171 
172         if (topElement == _parentElement) {
173 
174             // Append current element to its parent
175 
176             _closeOpenTag(topElement);
177 
178             _openElement(this);
179         }
180         else {
181             throw new IllegalArgumentException(
182                 "The parent element does not exist");
183         }
184     }
185 
186     private void _closeElement(Element element) {
187         _closeOpenTag(element);
188 
189         _stringBundler.append(_CLOSE_PRE);
190         _stringBundler.append(element._name);
191         _stringBundler.append(_CLOSE_POST);
192 
193         element._elementClosed = true;
194     }
195 
196     private void _closeOpenTag(Element element) {
197         if (element._openTagClosed == false) {
198             _stringBundler.append(_OPEN_POST);
199 
200             if (element._text != null) {
201                 _stringBundler.append(element._text);
202             }
203 
204             element._openTagClosed = true;
205         }
206     }
207 
208     private void _flushPendingOpenElements() {
209         while (_elementStack.size() > 0) {
210             _closeElement(_elementStack.removeLast());
211         }
212     }
213 
214     private String _formatText(String text) {
215         return HtmlUtil.escape(text);
216     }
217 
218     private void _openElement(Element element) {
219         _stringBundler.append(_OPEN_PRE).append(element._name);
220 
221         _elementStack.addLast(element);
222     }
223 
224     private static final String _CLOSE_POST = ">";
225 
226     private static final String _CLOSE_PRE = "</";
227 
228     private static final String _EQUAL_QUOTE = "=\"";
229 
230     private static final String _OPEN_POST = ">";
231 
232     private static final String _OPEN_PRE = "<";
233 
234     private static final String _XML_HEADER =
235         "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
236 
237     private boolean _elementClosed;
238     private LinkedList<Element> _elementStack;
239     private String _name;
240     private boolean _openTagClosed;
241     private Element _parentElement;
242     private StringBundler _stringBundler;
243     private String _text;
244     private String _xmlString;
245 
246 }