1 module hunt.xml.Attribute; 2 3 import hunt.xml.Common; 4 import hunt.xml.Document; 5 import hunt.xml.Element; 6 import hunt.xml.Node; 7 8 import std.format; 9 import std.string; 10 11 /** 12 * 13 */ 14 class Attribute : Node 15 { 16 protected Attribute m_prev_attribute; 17 protected Attribute m_next_attribute; 18 protected string m_xmlns; 19 protected string m_local_name; 20 protected string m_value; 21 22 23 this() { 24 super(NodeType.Attribute); 25 } 26 27 this(string name, string value) { 28 super(name, NodeType.Attribute); 29 m_value = value; 30 } 31 32 Document document() 33 { 34 if (Element node = m_parent) 35 { 36 while (node.m_parent) 37 node = node.m_parent; 38 return node.m_type == NodeType.Document ? cast(Document)(node) : null; 39 } 40 else 41 return null; 42 } 43 44 string xmlns() 45 { 46 if (m_xmlns) return m_xmlns; 47 char[] p; 48 char[] name = cast(char[])m_name.dup; 49 for (p = name; p.length > 0 && p[0] != ':'; p=p[1..$]) 50 { 51 if ((m_name.length - p.length) >= m_name.length) 52 break; 53 } 54 if (p.length == 0 || ((m_name.length - p.length) >= m_name.length)) { 55 m_xmlns = "nullstring"; 56 return m_xmlns; 57 } 58 Element element = m_parent; 59 if (element) 60 { 61 char []xmlns = cast(char[])m_xmlns; 62 element.lookupXmlns(xmlns, name[0 .. m_name.length - p.length]); 63 m_xmlns = cast(string)xmlns.dup; 64 } 65 return m_xmlns; 66 } 67 68 /// Gets previous attribute, optionally matching attribute name. 69 /// \param name Name of attribute to find, or 0 to return previous attribute regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero 70 /// \param name_size Size of name, in characters, or 0 to have size calculated automatically from string 71 /// \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters 72 /// \return Pointer to found attribute, or 0 if not found. 73 74 Attribute previousAttribute(string name = null, bool caseSensitive = true) 75 { 76 if (name.length > 0) { 77 if(caseSensitive) { 78 for (Attribute attribute = m_prev_attribute; attribute; attribute = attribute.m_prev_attribute) { 79 if (attribute.getName() == name) return attribute; 80 } 81 } else { 82 for (Attribute attribute = m_prev_attribute; attribute; attribute = attribute.m_prev_attribute) { 83 if (icmp(attribute.getName(), name) == 0) return attribute; 84 } 85 } 86 return null; 87 } else { 88 return m_parent is null ? null : m_prev_attribute; 89 } 90 } 91 92 void previousAttribute(Attribute attribute) { 93 m_prev_attribute = attribute; 94 } 95 96 /** 97 * Gets next attribute, optionally matching attribute name. 98 * 99 * Params: 100 * name = Name of attribute to find, or 0 to return next attribute regardless of its name; 101 * this string doesn't have to be zero-terminated if name_size is non-zero 102 * caseSensitive = Should name comparison be case-sensitive; non case-sensitive comparison 103 * works properly only for ASCII characters 104 * 105 * Returns: 106 * Pointer to found attribute, or 0 if not found. 107 */ 108 Attribute nextAttribute(string name = null , bool caseSensitive = true) { 109 if (name.length > 0) 110 { 111 if(caseSensitive) { 112 for (Attribute attribute = m_next_attribute; attribute !is null; attribute = attribute.m_next_attribute) { 113 if (attribute.getName() == name) 114 return attribute; 115 } 116 } else { 117 for (Attribute attribute = m_next_attribute; attribute !is null; attribute = attribute.m_next_attribute) { 118 if (icmp(attribute.getName(), name) == 0) 119 return attribute; 120 } 121 } 122 return null; 123 } 124 else { 125 return m_parent is null ? null : m_next_attribute; 126 } 127 } 128 129 void nextAttribute(Attribute attribute) { 130 m_next_attribute = attribute; 131 } 132 133 /** 134 * Returns the value of the attribute. This method returns the same value as 135 * the {@link Node#getText()}method. 136 * 137 * @return the value of the attribute 138 */ 139 string getValue() { 140 return m_value; 141 } 142 143 /** 144 * Sets the value of this attribute or this method will throw an 145 * <code>UnsupportedOperationException</code> if it is read-only. 146 * 147 * @param value is the new value of this attribute 148 */ 149 void setValue(string value) { 150 m_value = value; 151 } 152 153 string localName() { 154 if (m_local_name) return m_local_name; 155 string p = this.getName(); 156 m_local_name = p; 157 158 for (int i=0; i<p.length; ++i) { 159 if( p[i] == ':') { 160 m_local_name = p[i+1 .. $]; 161 break; 162 } 163 } 164 165 return m_local_name; 166 } 167 168 void localName(string name) { 169 m_local_name = name; 170 } 171 172 override string toString() { 173 return format("name: %s, value: %s", m_name, m_value); 174 } 175 }