1 /* |
|
2 * Copyright (c) 2007 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: CSSDOMProcessor applies given CSSRules to DOM Document. |
|
15 * |
|
16 */ |
|
17 |
|
18 |
|
19 package com.nokia.tools.themeinstaller.cssparser; |
|
20 |
|
21 import java.util.Collections; |
|
22 import java.util.HashMap; |
|
23 import java.util.Iterator; |
|
24 import java.util.Vector; |
|
25 |
|
26 import org.w3c.css.sac.LexicalUnit; |
|
27 import org.w3c.dom.Document; |
|
28 import org.w3c.dom.Element; |
|
29 import org.w3c.dom.NamedNodeMap; |
|
30 import org.w3c.dom.Node; |
|
31 import org.w3c.dom.traversal.DocumentTraversal; |
|
32 import org.w3c.dom.traversal.NodeFilter; |
|
33 import org.w3c.dom.traversal.NodeIterator; |
|
34 |
|
35 /** |
|
36 * CSSDOMProcessor applies given CSSRules to DOM Document. |
|
37 */ |
|
38 public class CSSDOMProcessor |
|
39 { |
|
40 /** The Constant STRING_PROPERTY. */ |
|
41 public static final String STRING_PROPERTY = "styleproperty"; |
|
42 |
|
43 /** The Constant STRING_PSEUDOCLASS. */ |
|
44 public static final String STRING_PSEUDOCLASS = "pseudoclass"; |
|
45 |
|
46 /** The Constant STRING_NAME. */ |
|
47 public static final String STRING_NAME = "name"; |
|
48 |
|
49 /** The Constant STRING_VALUE. */ |
|
50 public static final String STRING_VALUE = "value"; |
|
51 |
|
52 /** The Constant STRING_INHERIT. */ |
|
53 public static final String STRING_INHERIT = "inherit"; |
|
54 |
|
55 /** The Constant CHAR_COLON. */ |
|
56 private static final char CHAR_COLON = ':'; |
|
57 |
|
58 /** The Constant STRING_SEPARATOR. */ |
|
59 private static final String STRING_SEPARATOR = "|"; |
|
60 |
|
61 /** The Constant PSEUDO_TABLE. */ |
|
62 private static final String[] UNSTYLABLE_ELEMENTS_TABLE = { "styleproperty" }; |
|
63 |
|
64 /** The Element type resolver. */ |
|
65 private static ElementTypeResolver iElementTypeResolver = new ElementTypeResolver(); |
|
66 |
|
67 /** The Constant INHERITABLE_PROPERTIES. */ |
|
68 public static final String[] INHERITABLE_PROPERTIES = { "visibility", |
|
69 "block-progression", "direction", "color", "font-family", |
|
70 "font-size", "font-weight", "font-style", "_s60-tab-style", |
|
71 "_s60-tab-color" }; |
|
72 |
|
73 /** The Match Maker. */ |
|
74 private CSSMatchMaker iCSSMatchMaker; |
|
75 |
|
76 /** |
|
77 * Instantiates a new CSSDOM processor. |
|
78 */ |
|
79 public CSSDOMProcessor() |
|
80 { |
|
81 iCSSMatchMaker = new CSSMatchMaker(); |
|
82 } |
|
83 |
|
84 /** |
|
85 * Sort rules. |
|
86 * |
|
87 * @param rules The rules to be sorted by priority |
|
88 */ |
|
89 private static void sortRules( Vector rules ) |
|
90 { |
|
91 Collections.sort( rules ); |
|
92 } |
|
93 |
|
94 /** |
|
95 * Checks if is stylable element. |
|
96 * |
|
97 * @param aElement The element to be checked |
|
98 * |
|
99 * @return true, if is stylable element |
|
100 */ |
|
101 private static boolean isStylableElement(Element aElement){ |
|
102 |
|
103 for ( int i = 0; i < UNSTYLABLE_ELEMENTS_TABLE.length; i++ ) |
|
104 { |
|
105 if ( UNSTYLABLE_ELEMENTS_TABLE[ i ].equals( aElement.getTagName() )) |
|
106 { |
|
107 return false; |
|
108 } |
|
109 } |
|
110 |
|
111 return true; |
|
112 } |
|
113 |
|
114 /** |
|
115 * Apply style rule to DOM. Walks through the DOM tree elements and finds |
|
116 * those that match with the CSSRule Selector. If matching element is found, |
|
117 * Rule is applied to DOM Element. |
|
118 * |
|
119 * @param aDocument The DOM document to apply the rules |
|
120 * @param aRuleList List of CSS style rules |
|
121 */ |
|
122 public void applyRulesToDom( Document aDocument, |
|
123 Vector aRuleList ) |
|
124 { |
|
125 DocumentTraversal traversal = ( DocumentTraversal ) aDocument; |
|
126 |
|
127 NodeIterator iterator = traversal.createNodeIterator( aDocument |
|
128 .getDocumentElement(), NodeFilter.SHOW_ELEMENT, null, true ); |
|
129 |
|
130 for ( Node node = iterator.nextNode(); node != null; node = iterator |
|
131 .nextNode() ) |
|
132 { |
|
133 Element element = ( Element ) node; |
|
134 if ( isStylableElement(element) ) |
|
135 { |
|
136 Vector rulesMatch = new Vector(); |
|
137 |
|
138 for ( int i = 0; i < aRuleList.size(); i++ ) |
|
139 { |
|
140 |
|
141 CSSRule rule = ( CSSRule ) aRuleList.get( i ); |
|
142 |
|
143 if ( iCSSMatchMaker.match( rule, element ) ) |
|
144 { |
|
145 rulesMatch.add( rule ); |
|
146 } |
|
147 } |
|
148 |
|
149 sortRules( rulesMatch ); |
|
150 |
|
151 for ( int j = 0; j < rulesMatch.size(); j++ ) |
|
152 { |
|
153 CSSRule matchingRule = ( CSSRule ) rulesMatch.elementAt( j ); |
|
154 // if(matchingRule.getSelector().toString().equals("box:edit")){ |
|
155 // System.out.println("Party"); |
|
156 // } |
|
157 |
|
158 applyRuleToElement( element, matchingRule ); |
|
159 } |
|
160 } |
|
161 } |
|
162 applyInheritance( aDocument ); |
|
163 } |
|
164 |
|
165 |
|
166 /** |
|
167 * Checks if given property is inheritable property. |
|
168 * |
|
169 * @param aProperty the a property |
|
170 * |
|
171 * @return true, if is inheritable property |
|
172 */ |
|
173 public boolean isInheritableProperty( String aProperty ) |
|
174 { |
|
175 for ( int i = 0; i < INHERITABLE_PROPERTIES.length; i++ ) |
|
176 { |
|
177 if ( aProperty.equals( INHERITABLE_PROPERTIES[ i ] ) ) |
|
178 { |
|
179 return true; |
|
180 } |
|
181 } |
|
182 return false; |
|
183 } |
|
184 |
|
185 /** |
|
186 * Checks if given element can inherit given property name. |
|
187 * |
|
188 * @param aElement the a element |
|
189 * @param aPropertyName the a value's name |
|
190 * |
|
191 * @return true, if element can inherit the property |
|
192 */ |
|
193 public boolean canInherit( Element aElement, String aPropertyName ) |
|
194 { |
|
195 return canInherit( aElement, aPropertyName, null ); |
|
196 } |
|
197 |
|
198 /** |
|
199 * Checks if given element can inherit given property. |
|
200 * |
|
201 * If property value equals "inherit", the property |
|
202 * is interpreted as inherited. |
|
203 * |
|
204 * If property is inheritable and element can inherit |
|
205 * properties, the element can inherit the property. |
|
206 * |
|
207 * @param aElement the a element |
|
208 * @param aPropertyName the a property's name |
|
209 * @param aPropertyValue the a property's value |
|
210 * |
|
211 * @return true, if element can inherit the property |
|
212 */ |
|
213 public boolean canInherit( Element aElement, String aPropertyName, |
|
214 String aPropertyValue ) |
|
215 { |
|
216 if ( aPropertyValue != null && aPropertyValue.equals( STRING_INHERIT ) ) |
|
217 { |
|
218 return true; |
|
219 } |
|
220 |
|
221 if ( !isInheritableProperty( aPropertyName ) ) |
|
222 { |
|
223 return false; |
|
224 } |
|
225 |
|
226 if ( iElementTypeResolver.canInherit( aElement.getNodeName() ) ) |
|
227 { |
|
228 return true; |
|
229 } |
|
230 |
|
231 return false; |
|
232 } |
|
233 |
|
234 /** |
|
235 * Apply inheritance for stylable nodes that can inherit properties from |
|
236 * parent elements. |
|
237 * |
|
238 * @param aDocument The DOM document to be modified |
|
239 */ |
|
240 private void applyInheritance( Document aDocument ) |
|
241 { |
|
242 DocumentTraversal traversal = ( DocumentTraversal ) aDocument; |
|
243 |
|
244 NodeIterator iterator = traversal.createNodeIterator( aDocument |
|
245 .getDocumentElement(), NodeFilter.SHOW_ELEMENT, null, true ); |
|
246 |
|
247 for ( Node node = iterator.nextNode(); node != null; node = iterator |
|
248 .nextNode() ) |
|
249 { |
|
250 Element element = ( Element ) node; |
|
251 // if(node.getLocalName().equals("box")) |
|
252 // System.out.println("Kill me!!!"); |
|
253 if ( isStylableElement( element ) ) |
|
254 { |
|
255 if ( iElementTypeResolver.canInherit( element.getNodeName() ) ) |
|
256 { |
|
257 applyInheritance( element ); |
|
258 } |
|
259 } |
|
260 } |
|
261 } |
|
262 |
|
263 /** |
|
264 * Apply inheritance for DOM Element. Checks if any of the elements parents |
|
265 * has properties that can be inherited in the given element. If such |
|
266 * property is found, new property to the element is added, unless there |
|
267 * already exists a property with the same name. |
|
268 * |
|
269 * @param aElement The element to be modified |
|
270 */ |
|
271 private void applyInheritance( Element aElement ) |
|
272 { |
|
273 for ( int i = 0; i < INHERITABLE_PROPERTIES.length; i++ ) |
|
274 { |
|
275 String inheritableProperty = INHERITABLE_PROPERTIES[ i ]; |
|
276 if ( iElementTypeResolver.canInherit( aElement.getNodeName() ) ) |
|
277 { |
|
278 if ( !hasAttribute( aElement, inheritableProperty ) ) |
|
279 { |
|
280 if ( hasParentElementWithAttribute( aElement, |
|
281 inheritableProperty ) ) |
|
282 { |
|
283 if ( hasChildElementWithAttribute( aElement, |
|
284 STRING_PROPERTY, inheritableProperty ) == null ) |
|
285 { |
|
286 addNewChildElement( aElement, STRING_PROPERTY, |
|
287 inheritableProperty, |
|
288 LexicalUnit.SAC_IDENT |
|
289 + STRING_SEPARATOR + STRING_INHERIT ); |
|
290 } |
|
291 } |
|
292 } |
|
293 } |
|
294 } |
|
295 } |
|
296 |
|
297 /** |
|
298 * Checks for parent element with attribute name. |
|
299 * |
|
300 * @param aElement The element that's parents are checked |
|
301 * @param aAttributeName The name of the property |
|
302 * |
|
303 * @return true, aElement has parent node with given attribute name |
|
304 */ |
|
305 private static boolean hasParentElementWithAttribute( Element aElement, |
|
306 String aAttributeName ) |
|
307 { |
|
308 Node n = aElement.getParentNode(); |
|
309 while ( n != null ) |
|
310 { |
|
311 if ( n.getNodeType() == Node.ELEMENT_NODE ) |
|
312 { |
|
313 if ( hasChildElementWithAttribute( ( Element ) n, |
|
314 STRING_PROPERTY, aAttributeName ) != null ) |
|
315 { |
|
316 return true; |
|
317 } |
|
318 } |
|
319 n = n.getParentNode(); |
|
320 } |
|
321 return false; |
|
322 } |
|
323 |
|
324 /** |
|
325 * Apply rule to DOM Element. Creates child elements for aElement with style |
|
326 * data. If the element already has matching child element, the value of it |
|
327 * is overwritten. |
|
328 * |
|
329 * @param aElement The DOM Element |
|
330 * @param aRule CSS style rule |
|
331 */ |
|
332 private void applyRuleToElement( Element aElement, CSSRule aRule ) |
|
333 { |
|
334 HashMap styleMap = aRule.getStyleMap(); |
|
335 |
|
336 Iterator itKeys = styleMap.keySet().iterator(); |
|
337 while ( itKeys.hasNext() ) |
|
338 { |
|
339 String keyName = ( String ) itKeys.next(); |
|
340 |
|
341 // Case 1 : Rule has pseudo selector, add or replace Element |
|
342 if ( aRule.isPseudo() ) |
|
343 { |
|
344 String selectorString = aRule.getSelector().toString(); |
|
345 String pseudoPart = selectorString.substring( selectorString |
|
346 .lastIndexOf( CHAR_COLON ) + 1 ); |
|
347 |
|
348 Vector elementsAttributes = new Vector(); |
|
349 elementsAttributes.add( new NameValuePair(STRING_NAME, keyName) ); |
|
350 elementsAttributes.add( new NameValuePair(STRING_PSEUDOCLASS, pseudoPart) ); |
|
351 |
|
352 Element e = hasChildElementWithAttributes( aElement, |
|
353 STRING_PROPERTY, elementsAttributes ); |
|
354 if ( e != null && hasAttribute( e, STRING_NAME, keyName ) ) |
|
355 { |
|
356 |
|
357 CSSStyleProperty property = ( CSSStyleProperty ) styleMap |
|
358 .get( keyName ); |
|
359 Vector values = property.getValues(); |
|
360 |
|
361 CSSPropertyValue propertyValue = ( CSSPropertyValue ) values |
|
362 .elementAt( 0 ); |
|
363 |
|
364 // 1st value has name "value" |
|
365 e.setAttribute( STRING_VALUE, propertyValue |
|
366 .getValueTypeAndValue() ); |
|
367 |
|
368 // if there are more values, their name is set to "value1, |
|
369 // value 2, ..." |
|
370 for ( int i = 1; i < values.size(); i++ ) |
|
371 { |
|
372 |
|
373 propertyValue = ( CSSPropertyValue ) values |
|
374 .elementAt( i ); |
|
375 |
|
376 e.setAttribute( STRING_VALUE + i, propertyValue |
|
377 .getValueTypeAndValue() ); |
|
378 } |
|
379 } |
|
380 else |
|
381 { |
|
382 |
|
383 CSSStyleProperty property = ( CSSStyleProperty ) styleMap |
|
384 .get( keyName ); |
|
385 Vector values = property.getValues(); |
|
386 |
|
387 CSSPropertyValue propertyValue = ( CSSPropertyValue ) values |
|
388 .elementAt( 0 ); |
|
389 |
|
390 Element newElement = addNewChildElement( aElement, |
|
391 STRING_PROPERTY, keyName, propertyValue |
|
392 .getValueTypeAndValue(), pseudoPart ); |
|
393 |
|
394 // Rest of the values are set to element we just created |
|
395 for ( int i = 1; i < values.size(); i++ ) |
|
396 { |
|
397 propertyValue = ( CSSPropertyValue ) values |
|
398 .elementAt( i ); |
|
399 newElement.setAttribute( STRING_VALUE + i, |
|
400 propertyValue.getValueTypeAndValue() ); |
|
401 } |
|
402 } |
|
403 } |
|
404 // Case 2 : Rule don't have pseudo selector, add or replace Element |
|
405 else |
|
406 { |
|
407 Vector elementsAttributes = new Vector(); |
|
408 elementsAttributes.add( new NameValuePair(STRING_NAME, keyName) ); |
|
409 |
|
410 Element e = hasChildElementWithAttributes( aElement, |
|
411 STRING_PROPERTY, elementsAttributes ); |
|
412 |
|
413 if ( e != null && hasAttribute( e, STRING_NAME, keyName ) ) |
|
414 { |
|
415 CSSStyleProperty property = ( CSSStyleProperty ) styleMap |
|
416 .get( keyName ); |
|
417 Vector values = property.getValues(); |
|
418 |
|
419 CSSPropertyValue propertyValue = ( CSSPropertyValue ) values |
|
420 .elementAt( 0 ); |
|
421 |
|
422 // 1st value has name "value" |
|
423 e.setAttribute( STRING_VALUE, propertyValue |
|
424 .getValueTypeAndValue() ); |
|
425 |
|
426 // if there are more values, their name is set to "value1, |
|
427 // value 2, ..." |
|
428 for ( int i = 1; i < values.size(); i++ ) |
|
429 { |
|
430 propertyValue = ( CSSPropertyValue ) values |
|
431 .elementAt( i ); |
|
432 e.setAttribute( STRING_VALUE + i, propertyValue |
|
433 .getValueTypeAndValue() ); |
|
434 } |
|
435 } |
|
436 else |
|
437 { |
|
438 |
|
439 CSSStyleProperty property = ( CSSStyleProperty ) styleMap |
|
440 .get( keyName ); |
|
441 Vector values = property.getValues(); |
|
442 |
|
443 CSSPropertyValue propertyValue = ( CSSPropertyValue ) values |
|
444 .elementAt( 0 ); |
|
445 |
|
446 Element newElement = addNewChildElement( aElement, |
|
447 STRING_PROPERTY, keyName, propertyValue |
|
448 .getValueTypeAndValue() ); |
|
449 |
|
450 // Rest of the values are set to element we just created |
|
451 for ( int i = 1; i < values.size(); i++ ) |
|
452 { |
|
453 propertyValue = ( CSSPropertyValue ) values |
|
454 .elementAt( i ); |
|
455 newElement.setAttribute( STRING_VALUE + i, |
|
456 propertyValue.getValueTypeAndValue() ); |
|
457 } |
|
458 } |
|
459 } |
|
460 } |
|
461 } |
|
462 |
|
463 /** |
|
464 * Checks if DOM Element has a attribute with given value. |
|
465 * |
|
466 * @param aElement The DOM element to check |
|
467 * @param aValue Attributes value |
|
468 * |
|
469 * @return true, if successful |
|
470 */ |
|
471 private static boolean hasAttribute( Element aElement, String aValue ) |
|
472 { |
|
473 return hasAttribute( aElement, null, aValue ); |
|
474 } |
|
475 |
|
476 |
|
477 /** |
|
478 * Checks if DOM Element has a attribute with given name and value. |
|
479 * Attribute's name can be null, when only the attributes value is checked |
|
480 * |
|
481 * @param aElement The DOM element to check |
|
482 * @param aName Attributes name |
|
483 * @param aValue Attributes value |
|
484 * |
|
485 * @return true, if successful |
|
486 */ |
|
487 private static boolean hasAttribute( Element aElement, String aName, |
|
488 String aValue ) |
|
489 { |
|
490 if ( aElement == null ) |
|
491 { |
|
492 return false; |
|
493 } |
|
494 if ( aElement.hasAttributes() ) |
|
495 { |
|
496 NamedNodeMap nnm = aElement.getAttributes(); |
|
497 for ( int i = 0; i < nnm.getLength(); i++ ) |
|
498 { |
|
499 Node att = nnm.item( i ); |
|
500 if ( aName != null ) |
|
501 { |
|
502 if ( att.getNodeValue().equals( aValue ) |
|
503 && att.getNodeName().equals( aName ) ) |
|
504 { |
|
505 return true; |
|
506 } |
|
507 } |
|
508 else |
|
509 { |
|
510 if ( att.getNodeValue().equals( aValue ) ) |
|
511 { |
|
512 return true; |
|
513 } |
|
514 } |
|
515 } |
|
516 } |
|
517 return false; |
|
518 } |
|
519 |
|
520 /** |
|
521 * Checks for elements attributes. |
|
522 * |
|
523 * @param aElement The element to be checked |
|
524 * @param aAttributes Attributes in name-value pairs |
|
525 * |
|
526 * @return true, if element has attributes given in aAttributes |
|
527 */ |
|
528 private static boolean hasAttributes( Element aElement, Vector aAttributes ) |
|
529 { |
|
530 if ( aElement == null ) |
|
531 { |
|
532 return false; |
|
533 } |
|
534 |
|
535 if ( aElement.hasAttributes() ) |
|
536 { |
|
537 |
|
538 for ( int i = 0; i < aAttributes.size(); i++ ) |
|
539 { |
|
540 |
|
541 NameValuePair nameValuePair = ( NameValuePair ) aAttributes |
|
542 .get( i ); |
|
543 |
|
544 String name = nameValuePair.getName(); |
|
545 String value = nameValuePair.getValue(); |
|
546 |
|
547 if ( !hasAttribute( aElement, name, value ) ) |
|
548 { |
|
549 return false; |
|
550 } |
|
551 } |
|
552 } |
|
553 return true; |
|
554 } |
|
555 |
|
556 /** |
|
557 * Checks for child element with attribute's name. |
|
558 * |
|
559 * @param aParent The parent element |
|
560 * @param aElementName The element tag name to be matched with child nodes |
|
561 * name |
|
562 * @param aName Attributes name to be matched |
|
563 * |
|
564 * @return Child element with attribute, null if none |
|
565 */ |
|
566 private static Element hasChildElementWithAttribute( Element aParent, |
|
567 String aElementName, String aName ) |
|
568 { |
|
569 for ( Node n = aParent.getFirstChild(); n != null; n = n |
|
570 .getNextSibling() ) |
|
571 { |
|
572 if ( n.getNodeType() == Node.ELEMENT_NODE ) |
|
573 { |
|
574 if ( hasAttribute( ( Element ) n, aName ) |
|
575 && n.getNodeName().equals( aElementName ) ) |
|
576 { |
|
577 return ( Element ) n; |
|
578 } |
|
579 } |
|
580 } |
|
581 return null; |
|
582 } |
|
583 |
|
584 |
|
585 |
|
586 /** |
|
587 * Checks for child element with attributes. |
|
588 * |
|
589 * @param aParent The parent element |
|
590 * @param aElementName The element tag name to be matched with child nodes |
|
591 * name |
|
592 * @param aNameValuePairs The Name-Value pairs for attributes that need to be |
|
593 * found |
|
594 * |
|
595 * @return Child element with attributes, null if none |
|
596 */ |
|
597 private static Element hasChildElementWithAttributes( Element aParent, |
|
598 String aElementName, Vector aNameValuePairs ) |
|
599 { |
|
600 for ( Node n = aParent.getFirstChild(); n != null; n = n |
|
601 .getNextSibling() ) |
|
602 { |
|
603 if ( n.getNodeType() == Node.ELEMENT_NODE ) |
|
604 { |
|
605 if ( n.getNodeName().equals( aElementName ) |
|
606 && hasAttributes( ( Element ) n, aNameValuePairs ) ) |
|
607 { |
|
608 return ( Element ) n; |
|
609 } |
|
610 } |
|
611 } |
|
612 return null; |
|
613 } |
|
614 |
|
615 /** |
|
616 * Adds the new node to DOM. |
|
617 * |
|
618 * @param aParent The parent of the new node |
|
619 * @param aElementName Element name for new DOM node |
|
620 * @param aKeyName Attribute name for new DOM node |
|
621 * @param aKeyValue Attribute value for new DOM node |
|
622 */ |
|
623 private Element addNewChildElement( Element aParent, |
|
624 String aElementName, String aKeyName, String aKeyValue ) |
|
625 { |
|
626 return addNewChildElement( aParent, aElementName, aKeyName, aKeyValue, null ); |
|
627 } |
|
628 |
|
629 /** |
|
630 * Adds the new node to DOM. |
|
631 * |
|
632 * @param aParent The parent of the new node |
|
633 * @param aElementName Element name for new DOM node |
|
634 * @param aKeyName Attribute name for new DOM node |
|
635 * @param aKeyValue Attribute value for new DOM node |
|
636 * @param aPseudo Pseudo attribute value for the DOM node |
|
637 */ |
|
638 private Element addNewChildElement( Element aParent, String aElementName, |
|
639 String aKeyName, String aKeyValue, String aPseudo ) |
|
640 { |
|
641 Document document = aParent.getOwnerDocument(); |
|
642 |
|
643 String namespaceUri = aParent.getNamespaceURI(); |
|
644 |
|
645 Element newElement = document.createElementNS( namespaceUri, |
|
646 aElementName ); |
|
647 |
|
648 if ( aPseudo != null ) |
|
649 { |
|
650 newElement.setAttribute( STRING_PSEUDOCLASS, aPseudo ); |
|
651 } |
|
652 newElement.setAttribute( STRING_NAME, aKeyName ); |
|
653 newElement.setAttribute( STRING_VALUE, aKeyValue ); |
|
654 |
|
655 aParent.appendChild( newElement ); |
|
656 return newElement; |
|
657 } |
|
658 |
|
659 |
|
660 /** |
|
661 * Class for temporarily store Node's attribute name and value. |
|
662 */ |
|
663 private class NameValuePair |
|
664 { |
|
665 private String iName; |
|
666 |
|
667 private String iValue; |
|
668 |
|
669 NameValuePair( String aName, String aValue ) |
|
670 { |
|
671 iName = aName; |
|
672 iValue = aValue; |
|
673 } |
|
674 |
|
675 public String getName() |
|
676 { |
|
677 return iName; |
|
678 } |
|
679 |
|
680 public String getValue() |
|
681 { |
|
682 return iValue; |
|
683 } |
|
684 |
|
685 } |
|
686 |
|
687 } |
|