xref: /trunk/main/unoxml/source/dom/attr.cxx (revision 91144cd0085a7583d2099b982122deb2184ab956)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 #include <attr.hxx>
25 
26 #include <string.h>
27 
28 #include <boost/shared_ptr.hpp>
29 
30 #include <com/sun/star/xml/dom/DOMException.hdl>
31 #include <com/sun/star/xml/dom/events/XMutationEvent.hpp>
32 
33 #include <document.hxx>
34 
35 
36 namespace DOM
37 {
CAttr(CDocument const & rDocument,::osl::Mutex const & rMutex,xmlAttrPtr const pAttr)38     CAttr::CAttr(CDocument const& rDocument, ::osl::Mutex const& rMutex,
39             xmlAttrPtr const pAttr)
40         : CAttr_Base(rDocument, rMutex,
41                 NodeType_ATTRIBUTE_NODE, reinterpret_cast<xmlNodePtr>(pAttr))
42         , m_aAttrPtr(pAttr)
43     {
44     }
45 
GetNamespace(xmlNodePtr const pNode)46     xmlNsPtr CAttr::GetNamespace(xmlNodePtr const pNode)
47     {
48         if (!m_pNamespace.get()) {
49             return 0;
50         }
51         xmlChar const*const pUri(reinterpret_cast<xmlChar const*>(
52                 m_pNamespace->first.getStr()));
53         xmlChar const*const pPrefix(reinterpret_cast<xmlChar const*>(
54                 m_pNamespace->second.getStr()));
55         xmlNsPtr pNs = xmlSearchNs(pNode->doc, pNode, pPrefix);
56         if (pNs && (0 != xmlStrcmp(pNs->href, pUri))) {
57             return pNs;
58         }
59         pNs = xmlNewNs(pNode, pUri, pPrefix);
60         if (pNs) {
61             return pNs;
62         }
63         pNs = xmlSearchNsByHref(pNode->doc, pNode, pUri);
64         // if (!pNs) hmm... now what? throw?
65         if (!pNs) { OSL_TRACE("CAtttr: cannot create namespace"); }
66         return pNs;
67     }
68 
IsChildTypeAllowed(NodeType const nodeType)69     bool CAttr::IsChildTypeAllowed(NodeType const nodeType)
70     {
71         switch (nodeType) {
72             case NodeType_TEXT_NODE:
73             case NodeType_ENTITY_REFERENCE_NODE:
74                 return true;
75             default:
76                 return false;
77         }
78     }
79 
getNodeName()80     OUString SAL_CALL CAttr::getNodeName()
81     {
82         return getName();
83     }
getNodeValue()84     OUString SAL_CALL CAttr::getNodeValue()
85     {
86         return getValue();
87     }
getLocalName()88     OUString SAL_CALL CAttr::getLocalName()
89     {
90         return getName();
91     }
92 
93 
94     /**
95     Returns the name of this attribute.
96     */
getName()97     OUString SAL_CALL CAttr::getName()
98     {
99         ::osl::MutexGuard const g(m_rMutex);
100 
101         if ((0 == m_aNodePtr) || (0 == m_aAttrPtr)) {
102             return ::rtl::OUString();
103         }
104         OUString const aName((char*)m_aAttrPtr->name,
105                 strlen((char*)m_aAttrPtr->name), RTL_TEXTENCODING_UTF8);
106         return aName;
107     }
108 
109     /**
110     The Element node this attribute is attached to or null if this
111     attribute is not in use.
112     */
getOwnerElement()113     Reference< XElement > SAL_CALL CAttr::getOwnerElement()
114     {
115         ::osl::MutexGuard const g(m_rMutex);
116 
117         if ((0 == m_aNodePtr) || (0 == m_aAttrPtr)) {
118             return 0;
119         }
120         if (0 == m_aAttrPtr->parent) {
121             return 0;
122         }
123         Reference< XElement > const xRet(
124             static_cast< XNode* >(GetOwnerDocument().GetCNode(
125                     m_aAttrPtr->parent).get()),
126             UNO_QUERY_THROW);
127         return xRet;
128     }
129 
130     /**
131     If this attribute was explicitly given a value in the original
132     document, this is true; otherwise, it is false.
133     */
getSpecified()134     sal_Bool SAL_CALL CAttr::getSpecified()
135     {
136         // FIXME if this DOM implementation supported DTDs it would need
137         // to check that this attribute is not default or something
138         return sal_True;
139     }
140 
141     /**
142     On retrieval, the value of the attribute is returned as a string.
143     */
getValue()144     OUString SAL_CALL CAttr::getValue()
145     {
146         ::osl::MutexGuard const g(m_rMutex);
147 
148         if ((0 == m_aNodePtr) || (0 == m_aAttrPtr)) {
149             return ::rtl::OUString();
150         }
151         if (0 == m_aAttrPtr->children) {
152             return ::rtl::OUString();
153         }
154         char const*const pContent((m_aAttrPtr->children)
155             ? reinterpret_cast<char const*>(m_aAttrPtr->children->content)
156             : "");
157         OUString const ret(pContent, strlen(pContent), RTL_TEXTENCODING_UTF8);
158         return ret;
159     }
160 
161     /**
162     Sets the value of the attribute from a string.
163     */
setValue(const OUString & value)164     void SAL_CALL CAttr::setValue(const OUString& value)
165     {
166         ::osl::ClearableMutexGuard guard(m_rMutex);
167 
168         if ((0 == m_aNodePtr) || (0 == m_aAttrPtr)) {
169             return;
170         }
171 
172         // remember old value (for mutation event)
173         OUString sOldValue = getValue();
174 
175         OString o1 = OUStringToOString(value, RTL_TEXTENCODING_UTF8);
176         xmlChar* xValue = (xmlChar*)o1.getStr();
177         // xmlChar* xName = OUStringToOString(m_aAttrPtr->name, RTL_TEXTENCODING_UTF8).getStr();
178         // this does not work if the attribute was created anew
179         // xmlNodePtr pNode = m_aAttrPtr->parent;
180         // xmlSetProp(pNode, m_aAttrPtr->name, xValue);
181         ::boost::shared_ptr<xmlChar const> const buffer(
182                 xmlEncodeEntitiesReentrant(m_aAttrPtr->doc, xValue), xmlFree);
183         xmlFreeNodeList(m_aAttrPtr->children);
184         m_aAttrPtr->children =
185             xmlStringGetNodeList(m_aAttrPtr->doc, buffer.get());
186         xmlNodePtr tmp = m_aAttrPtr->children;
187         while (tmp != NULL) {
188             tmp->parent = (xmlNodePtr) m_aNodePtr;
189             tmp->doc = m_aAttrPtr->doc;
190             if (tmp->next == NULL)
191                 m_aNodePtr->last = tmp;
192             tmp = tmp->next;
193         }
194 
195         // dispatch DOM events to signal change in attribute value
196         // dispatch DomAttrModified + DOMSubtreeModified
197         OUString sEventName( RTL_CONSTASCII_USTRINGPARAM("DOMAttrModified") );
198         Reference< XDocumentEvent > docevent(getOwnerDocument(), UNO_QUERY);
199         Reference< XMutationEvent > event(docevent->createEvent(sEventName),UNO_QUERY);
200         event->initMutationEvent(
201                 sEventName, sal_True, sal_False,
202                 Reference<XNode>( static_cast<XAttr*>( this ) ),
203                 sOldValue, value, getName(), AttrChangeType_MODIFICATION );
204 
205         guard.clear(); // release mutex before calling event handlers
206 
207         dispatchEvent(Reference< XEvent >(event, UNO_QUERY));
208         dispatchSubtreeModified();
209     }
210 
setPrefix(const OUString & prefix)211     void SAL_CALL CAttr::setPrefix(const OUString& prefix)
212     {
213         ::osl::MutexGuard const g(m_rMutex);
214 
215         if (!m_aNodePtr) { return; }
216 
217         if (m_pNamespace.get()) {
218             OSL_ASSERT(!m_aNodePtr->parent);
219             m_pNamespace->second =
220                 OUStringToOString(prefix, RTL_TEXTENCODING_UTF8);
221         } else {
222             CNode::setPrefix(prefix);
223         }
224     }
225 
getPrefix()226     OUString SAL_CALL CAttr::getPrefix()
227     {
228         ::osl::MutexGuard const g(m_rMutex);
229 
230         if (!m_aNodePtr) { return ::rtl::OUString(); }
231 
232         if (m_pNamespace.get()) {
233             OSL_ASSERT(!m_aNodePtr->parent);
234             OUString const ret(::rtl::OStringToOUString(
235                         m_pNamespace->second, RTL_TEXTENCODING_UTF8));
236             return ret;
237         } else {
238             return CNode::getPrefix();
239         }
240     }
241 
getNamespaceURI()242     OUString SAL_CALL CAttr::getNamespaceURI()
243     {
244         ::osl::MutexGuard const g(m_rMutex);
245 
246         if (!m_aNodePtr) { return ::rtl::OUString(); }
247 
248         if (m_pNamespace.get()) {
249             OSL_ASSERT(!m_aNodePtr->parent);
250             OUString const ret(::rtl::OStringToOUString(
251                         m_pNamespace->first, RTL_TEXTENCODING_UTF8));
252             return ret;
253         } else {
254             return CNode::getNamespaceURI();
255         }
256     }
257 }
258