xref: /trunk/main/xmloff/source/core/nmspmap.cxx (revision 63bba73c)
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 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_xmloff.hxx"
26 #include <tools/debug.hxx>
27 #include <rtl/ustring.hxx>
28 #include <rtl/ustrbuf.hxx>
29 
30 #ifndef _XMLTOKEN_HXX
31 #include <xmloff/xmltoken.hxx>
32 #endif
33 #include <xmloff/nmspmap.hxx>
34 
35 #include "xmloff/xmlnmspe.hxx"
36 
37 
38 using ::rtl::OUString;
39 using ::rtl::OUStringBuffer;
40 using namespace ::xmloff::token;
41 
42 /* The basic idea of this class is that we have two two ways to search our
43  * data...by prefix and by key. We use an STL hash_map for fast prefix
44  * searching and an STL map for fast key searching.
45  *
46  * The references to an 'Index' refer to an earlier implementation of the
47  * name space map and remain to support code which uses these interfaces.
48  *
49  * In this implementation, key and index should always be the same number.
50  *
51  * All references to Indices are now deprecated and the corresponding
52  * 'Key' methods should be used instead
53  *
54  * Martin 13/06/01
55  */
56 
SvXMLNamespaceMap()57 SvXMLNamespaceMap::SvXMLNamespaceMap()
58 : sXMLNS( GetXMLToken ( XML_XMLNS ) )
59 {
60 }
61 
SvXMLNamespaceMap(const SvXMLNamespaceMap & rMap)62 SvXMLNamespaceMap::SvXMLNamespaceMap( const SvXMLNamespaceMap& rMap )
63 : sXMLNS( GetXMLToken ( XML_XMLNS ) )
64 {
65 	aNameHash = rMap.aNameHash;
66 	aNameMap  = rMap.aNameMap;
67 }
68 
operator =(const SvXMLNamespaceMap & rMap)69 void SvXMLNamespaceMap::operator=( const SvXMLNamespaceMap& rMap )
70 {
71     aNameHash = rMap.aNameHash;
72     aNameMap = rMap.aNameMap;
73 }
74 
~SvXMLNamespaceMap()75 SvXMLNamespaceMap::~SvXMLNamespaceMap()
76 {
77 	QNameCache::iterator aIter = aQNameCache.begin(), aEnd = aQNameCache.end();
78 	while ( aIter != aEnd )
79 	{
80 		const OUString *pString = (*aIter).first.second;
81 		aIter++;
82 		delete pString;
83     }
84 }
85 
operator ==(const SvXMLNamespaceMap & rCmp) const86 int SvXMLNamespaceMap::operator ==( const SvXMLNamespaceMap& rCmp ) const
87 {
88 	return static_cast < int > (aNameHash == rCmp.aNameHash);
89 }
90 
_Add(const OUString & rPrefix,const OUString & rName,sal_uInt16 nKey)91 sal_uInt16 SvXMLNamespaceMap::_Add( const OUString& rPrefix, const OUString &rName, sal_uInt16 nKey )
92 {
93 	if( XML_NAMESPACE_UNKNOWN == nKey )
94 	{
95 		// create a new unique key with UNKNOWN flag set
96 		nKey = XML_NAMESPACE_UNKNOWN_FLAG;
97 		do
98 		{
99 			NameSpaceMap::const_iterator aIter = aNameMap.find ( nKey );
100 			if( aIter == aNameMap.end() )
101 				break;
102 			nKey++;
103 		}
104 		while ( sal_True );
105 	}
106     ::vos::ORef<NameSpaceEntry> pEntry(new NameSpaceEntry);
107 	pEntry->sName   = rName;
108 	pEntry->nKey    = nKey;
109 	pEntry->sPrefix = rPrefix;
110 	aNameHash[ rPrefix ] = pEntry;
111 	aNameMap [ nKey ]	 = pEntry;
112 	return nKey;
113 }
114 
Add(const OUString & rPrefix,const OUString & rName,sal_uInt16 nKey)115 sal_uInt16 SvXMLNamespaceMap::Add( const OUString& rPrefix, const OUString& rName,
116 							   sal_uInt16 nKey )
117 {
118 	if( XML_NAMESPACE_UNKNOWN == nKey )
119 		nKey = GetKeyByName( rName );
120 
121 	DBG_ASSERT( XML_NAMESPACE_NONE != nKey,
122 				"SvXMLNamespaceMap::Add: invalid namespace key" );
123 
124 	if( XML_NAMESPACE_NONE == nKey )
125 		return USHRT_MAX;
126 
127 	if ( aNameHash.find ( rPrefix ) == aNameHash.end() )
128 		nKey = _Add( rPrefix, rName, nKey );
129 
130 	return nKey;
131 }
132 
AddIfKnown(const OUString & rPrefix,const OUString & rName)133 sal_uInt16 SvXMLNamespaceMap::AddIfKnown( const OUString& rPrefix, const OUString& rName )
134 {
135 	sal_uInt16 nKey = GetKeyByName( rName );
136 
137 	DBG_ASSERT( XML_NAMESPACE_NONE != nKey,
138 				"SvXMLNamespaceMap::AddIfKnown: invalid namespace key" );
139 
140 	if( XML_NAMESPACE_NONE == nKey )
141 		return XML_NAMESPACE_UNKNOWN;
142 
143 	if( XML_NAMESPACE_UNKNOWN != nKey )
144     {
145         NameSpaceHash::const_iterator aIter = aNameHash.find( rPrefix );
146         if( aIter == aNameHash.end() || (*aIter).second->sName != rName )
147             nKey = _Add( rPrefix, rName, nKey );
148     }
149 
150 	return nKey;
151 }
152 
153 
GetKeyByPrefix(const OUString & rPrefix) const154 sal_uInt16 SvXMLNamespaceMap::GetKeyByPrefix( const OUString& rPrefix ) const
155 {
156 	NameSpaceHash::const_iterator aIter = aNameHash.find(rPrefix);
157 	return (aIter != aNameHash.end()) ? (*aIter).second->nKey : USHRT_MAX;
158 }
159 
GetKeyByName(const OUString & rName) const160 sal_uInt16 SvXMLNamespaceMap::GetKeyByName( const OUString& rName ) const
161 {
162 	sal_uInt16 nKey = XML_NAMESPACE_UNKNOWN;
163 	NameSpaceHash::const_iterator aIter = aNameHash.begin(), aEnd = aNameHash.end();
164 	while (aIter != aEnd )
165 	{
166 		if ((*aIter).second->sName == rName)
167 		{
168 			nKey = (*aIter).second->nKey;
169 			break;
170 		}
171 		aIter++;
172 	}
173 	return nKey;
174 }
175 
GetPrefixByKey(sal_uInt16 nKey) const176 const OUString& SvXMLNamespaceMap::GetPrefixByKey( sal_uInt16 nKey ) const
177 {
178 	NameSpaceMap::const_iterator aIter = aNameMap.find (nKey);
179 	return (aIter != aNameMap.end()) ? (*aIter).second->sPrefix : sEmpty;
180 }
181 
GetNameByKey(sal_uInt16 nKey) const182 const OUString& SvXMLNamespaceMap::GetNameByKey( sal_uInt16 nKey ) const
183 {
184 	NameSpaceMap::const_iterator aIter = aNameMap.find (nKey);
185 	return (aIter != aNameMap.end()) ? (*aIter).second->sName : sEmpty;
186 }
187 
GetAttrNameByKey(sal_uInt16 nKey) const188 OUString SvXMLNamespaceMap::GetAttrNameByKey( sal_uInt16 nKey ) const
189 {
190 	OUStringBuffer sAttrName;
191 	NameSpaceMap::const_iterator aIter = aNameMap.find ( nKey );
192 	if (aIter != aNameMap.end())
193 	{
194 		sAttrName.append( sXMLNS  );
195         const ::rtl::OUString & prefix( (*aIter).second->sPrefix );
196         if (prefix.getLength()) // not default namespace
197         {
198             sAttrName.append( sal_Unicode(':') );
199             sAttrName.append( prefix );
200         }
201 	}
202 	return sAttrName.makeStringAndClear();
203 }
204 
GetQNameByKey(sal_uInt16 nKey,const OUString & rLocalName,sal_Bool bCache) const205 OUString SvXMLNamespaceMap::GetQNameByKey( sal_uInt16 nKey,
206 							const OUString& rLocalName,
207                             sal_Bool bCache) const
208 {
209 	// We always want to return at least the rLocalName...
210 
211 	switch ( nKey )
212 	{
213 		case XML_NAMESPACE_UNKNOWN:
214 			// ...if it's a completely unknown namespace, assert and return the local name
215 			DBG_ASSERT( sal_False, "SvXMLNamespaceMap::GetQNameByKey: invalid namespace key" );
216 		case XML_NAMESPACE_NONE:
217 			// ...if there isn't one, return the local name
218 			return rLocalName;
219 		case XML_NAMESPACE_XMLNS:
220 		{
221 			// ...if it's in the xmlns namespace, make the prefix
222 			// don't bother caching this, it rarely happens
223 			OUStringBuffer sQName;
224 			sQName.append ( sXMLNS );
225             if (rLocalName.getLength()) // not default namespace
226             {
227                 sQName.append ( sal_Unicode(':') );
228                 sQName.append ( rLocalName );
229             }
230 			return sQName.makeStringAndClear();;
231 		}
232 		case XML_NAMESPACE_XML:
233 		{
234             // this namespace is reserved, and needs not to be declared
235 			OUStringBuffer sQName;
236 			sQName.append ( GetXMLToken(XML_XML) );
237 			sQName.append ( sal_Unicode(':') );
238 			sQName.append ( rLocalName );
239 			return sQName.makeStringAndClear();;
240 		}
241 		default:
242 		{
243             QNameCache::const_iterator aQCacheIter;
244             if (bCache)
245 			    aQCacheIter = aQNameCache.find ( QNamePair ( nKey, &rLocalName ) );
246             else
247                 aQCacheIter = aQNameCache.end();
248 			if ( aQCacheIter != aQNameCache.end() )
249 				return (*aQCacheIter).second;
250 			else
251 			{
252 				NameSpaceMap::const_iterator aIter = aNameMap.find ( nKey );
253 				if ( aIter != aNameMap.end() )
254 				{
255 					OUStringBuffer sQName;
256 					// ...if it's in our map, make the prefix
257                     const OUString & prefix( (*aIter).second->sPrefix );
258                     if (prefix.getLength()) // not default namespace
259                     {
260                         sQName.append( prefix );
261                         sQName.append( sal_Unicode(':') );
262                     }
263                     sQName.append ( rLocalName );
264                     if (bCache)
265                     {
266                         OUString sString(sQName.makeStringAndClear());
267                         OUString *pString = new OUString ( rLocalName );
268                         const_cast < QNameCache * > (&aQNameCache)->operator[] ( QNamePair ( nKey, pString ) ) = sString;
269                         return sString;
270                     }
271                     else
272                         return sQName.makeStringAndClear();
273 				}
274 				else
275 				{
276 					// ... if it isn't, this is a Bad Thing, assert and return the local name
277 					DBG_ASSERT( sal_False, "SvXMLNamespaceMap::GetQNameByKey: invalid namespace key" );
278 					return rLocalName;
279 				}
280 			}
281 		}
282 	}
283 }
284 
_GetKeyByAttrName(const OUString & rAttrName,OUString * pLocalName,sal_Bool bCache) const285 sal_uInt16 SvXMLNamespaceMap::_GetKeyByAttrName(
286 							const OUString& rAttrName,
287 							OUString *pLocalName,
288                             sal_Bool bCache) const
289 {
290 	return _GetKeyByAttrName( rAttrName, 0, pLocalName, 0, bCache );
291 }
292 
_GetKeyByAttrName(const OUString & rAttrName,OUString * pPrefix,OUString * pLocalName,OUString * pNamespace,sal_Bool bCache) const293 sal_uInt16 SvXMLNamespaceMap::_GetKeyByAttrName( const OUString& rAttrName,
294 											OUString *pPrefix,
295 											OUString *pLocalName,
296 											OUString *pNamespace,
297                                             sal_Bool bCache) const
298 {
299 	sal_uInt16 nKey = XML_NAMESPACE_UNKNOWN;
300 
301     NameSpaceHash::const_iterator it;
302     if (bCache)
303         it = aNameCache.find ( rAttrName );
304     else
305         it = aNameCache.end();
306     if ( it != aNameCache.end() )
307 	{
308         const NameSpaceEntry &rEntry = (*it).second.getBody();
309         if ( pPrefix )
310             *pPrefix = rEntry.sPrefix;
311         if ( pLocalName )
312             *pLocalName = rEntry.sName;
313         nKey = rEntry.nKey;
314         if ( pNamespace )
315 		{
316             NameSpaceMap::const_iterator aMapIter = aNameMap.find (nKey);
317             *pNamespace = aMapIter != aNameMap.end() ? (*aMapIter).second->sName : sEmpty;
318         }
319     }
320     else
321     {
322 	vos::ORef<NameSpaceEntry> xEntry(new NameSpaceEntry());
323 
324         sal_Int32 nColonPos = rAttrName.indexOf( sal_Unicode(':') );
325         if( -1L == nColonPos )
326         {
327             // case: no ':' found -> default namespace
328             xEntry->sPrefix = OUString();
329             xEntry->sName = rAttrName;
330         }
331         else
332         {
333             // normal case: ':' found -> get prefix/suffix
334             xEntry->sPrefix = rAttrName.copy( 0L, nColonPos );
335             xEntry->sName = rAttrName.copy( nColonPos + 1L );
336         }
337 
338         if( pPrefix )
339             *pPrefix = xEntry->sPrefix;
340         if( pLocalName )
341             *pLocalName = xEntry->sName;
342 
343         NameSpaceHash::const_iterator aIter = aNameHash.find( xEntry->sPrefix );
344         if ( aIter != aNameHash.end() )
345 		{
346             // found: retrieve namespace key
347             nKey = xEntry->nKey = (*aIter).second->nKey;
348             if ( pNamespace )
349                 *pNamespace = (*aIter).second->sName;
350         }
351         else if ( xEntry->sPrefix == sXMLNS )
352             // not found, but xmlns prefix: return xmlns 'namespace'
353             nKey = xEntry->nKey = XML_NAMESPACE_XMLNS;
354         else if( nColonPos == -1L )
355             // not found, and no namespace: 'namespace' none
356             nKey = xEntry->nKey = XML_NAMESPACE_NONE;
357 
358         if (bCache)
359 	{
360 	    typedef std::pair< const rtl::OUString, vos::ORef<NameSpaceEntry> > value_type;
361 	    (void) const_cast<NameSpaceHash*>(&aNameCache)->insert (value_type (rAttrName, xEntry));
362 	}
363     }
364 
365 	return nKey;
366 }
367 
GetFirstKey() const368 sal_uInt16 SvXMLNamespaceMap::GetFirstKey() const
369 {
370 	return aNameMap.empty() ? USHRT_MAX : (*aNameMap.begin()).second->nKey;
371 }
372 
GetNextKey(sal_uInt16 nLastKey) const373 sal_uInt16 SvXMLNamespaceMap::GetNextKey( sal_uInt16 nLastKey ) const
374 {
375 	NameSpaceMap::const_iterator aIter = aNameMap.find ( nLastKey );
376 	return (++aIter == aNameMap.end()) ? USHRT_MAX : (*aIter).second->nKey;
377 }
378 
379 
380 // All methods after this are deprecated...
381 
GetKeyByIndex(sal_uInt16 nIdx) const382 sal_uInt16 SvXMLNamespaceMap::GetKeyByIndex( sal_uInt16 nIdx ) const
383 {
384 	return nIdx;
385 }
386 
GetIndexByKey(sal_uInt16 nKey) const387 sal_uInt16 SvXMLNamespaceMap::GetIndexByKey( sal_uInt16 nKey ) const
388 {
389 	return nKey;
390 }
GetFirstIndex() const391 sal_uInt16 SvXMLNamespaceMap::GetFirstIndex() const
392 {
393 	return aNameMap.empty() ? USHRT_MAX : (*aNameMap.begin()).second->nKey;
394 }
395 
GetNextIndex(sal_uInt16 nOldIdx) const396 sal_uInt16 SvXMLNamespaceMap::GetNextIndex( sal_uInt16 nOldIdx ) const
397 {
398 	NameSpaceMap::const_iterator aIter = aNameMap.find ( nOldIdx );
399 	return (++aIter == aNameMap.end()) ? USHRT_MAX : (*aIter).second->nKey;
400 }
401 
AddAtIndex(sal_uInt16,const OUString & rPrefix,const OUString & rName,sal_uInt16 nKey)402 sal_Bool SvXMLNamespaceMap::AddAtIndex( sal_uInt16 /*nIdx*/, const OUString& rPrefix,
403 									const OUString& rName, sal_uInt16 nKey )
404 {
405 	sal_Bool bRet = sal_False;
406 
407 	if( XML_NAMESPACE_UNKNOWN == nKey )
408 		nKey = GetKeyByName( rName );
409 
410 	DBG_ASSERT( XML_NAMESPACE_NONE != nKey,
411 				"SvXMLNamespaceMap::AddAtIndex: invalid namespace key" );
412 	if( XML_NAMESPACE_NONE != nKey && ! ( aNameHash.count ( rPrefix ) ) )
413 	{
414 		_Add( rPrefix, rName, nKey );
415 		bRet = sal_True;
416 	}
417 	return bRet;
418 }
419 
AddAtIndex(sal_uInt16 nIdx,const sal_Char * pPrefix,const sal_Char * pName,sal_uInt16 nKey)420 sal_Bool SvXMLNamespaceMap::AddAtIndex( sal_uInt16 nIdx, const sal_Char *pPrefix,
421 					 				const sal_Char *pName, sal_uInt16 nKey )
422 {
423 	OUString sPrefix( OUString::createFromAscii(pPrefix) );
424 	OUString sName( OUString::createFromAscii(pName) );
425 
426 	return AddAtIndex( nIdx, sPrefix, sName, nKey );
427 }
428 
GetAttrNameByIndex(sal_uInt16 nIdx) const429 OUString SvXMLNamespaceMap::GetAttrNameByIndex( sal_uInt16 nIdx ) const
430 {
431 	return GetAttrNameByKey( nIdx );
432 }
433 
GetQNameByIndex(sal_uInt16 nIdx,const OUString & rLocalName) const434 OUString SvXMLNamespaceMap::GetQNameByIndex( sal_uInt16 nIdx,
435 										   const OUString& rLocalName ) const
436 {
437 	return GetQNameByKey( nIdx, rLocalName );
438 }
439 
GetPrefixByIndex(sal_uInt16 nIdx) const440 const OUString& SvXMLNamespaceMap::GetPrefixByIndex( sal_uInt16 nIdx ) const
441 {
442 	NameSpaceMap::const_iterator aIter = aNameMap.find (nIdx);
443 	return (aIter != aNameMap.end()) ? (*aIter).second->sPrefix : sEmpty;
444 }
445 
GetNameByIndex(sal_uInt16 nIdx) const446 const OUString& SvXMLNamespaceMap::GetNameByIndex( sal_uInt16 nIdx ) const
447 {
448 	NameSpaceMap::const_iterator aIter = aNameMap.find (nIdx);
449 	return (aIter != aNameMap.end()) ? (*aIter).second->sName : sEmpty;
450 }
451 
GetIndexByPrefix(const OUString & rPrefix) const452 sal_uInt16 SvXMLNamespaceMap::GetIndexByPrefix( const OUString& rPrefix ) const
453 {
454 	NameSpaceHash::const_iterator aIter = aNameHash.find(rPrefix);
455 	return (aIter != aNameHash.end()) ? (*aIter).second->nKey : USHRT_MAX;
456 }
GetKeyByAttrName(const OUString & rAttrName,OUString * pLocalName,sal_uInt16) const457 sal_uInt16 SvXMLNamespaceMap::GetKeyByAttrName(
458 							const OUString& rAttrName,
459 							OUString *pLocalName,
460 							sal_uInt16 /*nIdxGuess*/) const
461 {
462 	return _GetKeyByAttrName( rAttrName, 0, pLocalName, 0 );
463 }
464 
GetKeyByAttrName(const OUString & rAttrName,OUString * pPrefix,OUString * pLocalName,OUString * pNamespace,sal_uInt16) const465 sal_uInt16 SvXMLNamespaceMap::GetKeyByAttrName( const OUString& rAttrName,
466 											OUString *pPrefix,
467 											OUString *pLocalName,
468 											OUString *pNamespace,
469 											sal_uInt16 /*nIdxGuess*/ ) const
470 {
471 	return _GetKeyByAttrName ( rAttrName, pPrefix, pLocalName, pNamespace );
472 }
473 
NormalizeURI(::rtl::OUString & rName)474 sal_Bool SvXMLNamespaceMap::NormalizeURI( ::rtl::OUString& rName )
475 {
476     // try OASIS + W3 URI normalization
477     sal_Bool bSuccess = NormalizeOasisURN( rName );
478     if( ! bSuccess )
479         bSuccess = NormalizeW3URI( rName );
480     return bSuccess;
481 }
482 
NormalizeW3URI(::rtl::OUString & rName)483 sal_Bool SvXMLNamespaceMap::NormalizeW3URI( ::rtl::OUString& rName )
484 {
485     // check if URI matches:
486     // http://www.w3.org/[0-9]*/[:letter:]*
487     //                   (year)/(WG name)
488     // For the following WG/standards names:
489     // - xforms
490 
491     sal_Bool bSuccess = sal_False;
492 	const OUString sURIPrefix = GetXMLToken( XML_URI_W3_PREFIX );
493     if( rName.compareTo( sURIPrefix, sURIPrefix.getLength() ) == 0 )
494     {
495         const OUString sURISuffix = GetXMLToken( XML_URI_XFORMS_SUFFIX );
496         sal_Int32 nCompareFrom = rName.getLength() - sURISuffix.getLength();
497         if( rName.copy( nCompareFrom ).equals( sURISuffix ) )
498         {
499             // found W3 prefix, and xforms suffix
500             rName = GetXMLToken( XML_N_XFORMS_1_0 );
501             bSuccess = sal_True;
502         }
503     }
504     return bSuccess;
505 }
506 
NormalizeOasisURN(::rtl::OUString & rName)507 sal_Bool SvXMLNamespaceMap::NormalizeOasisURN( ::rtl::OUString& rName )
508 {
509 	// #i38644#
510 	// we exported the wrong namespace for smil, so we correct this here on load
511 	// for older documents
512 	if( IsXMLToken( rName, ::xmloff::token::XML_N_SVG ) )
513 	{
514 		rName = GetXMLToken( ::xmloff::token::XML_N_SVG_COMPAT );
515 		return sal_True;
516 	}
517 	else if( IsXMLToken( rName, ::xmloff::token::XML_N_FO ) )
518 	{
519 		rName = GetXMLToken( ::xmloff::token::XML_N_FO_COMPAT );
520 		return sal_True;
521 	}
522 	else if( IsXMLToken( rName, ::xmloff::token::XML_N_SMIL ) ||
523 		  	 IsXMLToken( rName, ::xmloff::token::XML_N_SMIL_OLD )  )
524 	{
525 		rName = GetXMLToken( ::xmloff::token::XML_N_SMIL_COMPAT );
526 		return sal_True;
527 	}
528 
529 	//
530 	// Check if URN matches
531 	// :urn:oasis:names:tc:[^:]*:xmlns:[^:]*:1.[^:]*
532 	//                     |---|       |---| |-----|
533 	//                     TC-Id      Sub-Id Version
534 
535 	sal_Int32 nNameLen = rName.getLength();
536 	// :urn:oasis:names:tc.*
537 	const OUString& rOasisURN = GetXMLToken( XML_URN_OASIS_NAMES_TC );
538 	if( 0 != rName.compareTo( rOasisURN, rOasisURN.getLength() ) )
539 		return sal_False;
540 
541 	// :urn:oasis:names:tc:.*
542 	sal_Int32 nPos = rOasisURN.getLength();
543 	if( nPos >= nNameLen || rName[nPos] != ':' )
544 		return sal_False;
545 
546 	// :urn:oasis:names:tc:[^:]:.*
547 	sal_Int32 nTCIdStart = nPos+1;
548 	sal_Int32 nTCIdEnd = rName.indexOf( ':', nTCIdStart );
549 	if( -1 == nTCIdEnd )
550 		return sal_False;
551 
552 	// :urn:oasis:names:tc:[^:]:xmlns.*
553 	nPos = nTCIdEnd + 1;
554 	OUString sTmp( rName.copy( nPos ) );
555 	const OUString& rXMLNS = GetXMLToken( XML_XMLNS );
556 	if( 0!= sTmp.compareTo( rXMLNS, rXMLNS.getLength() ) )
557 		return sal_False;
558 
559 	// :urn:oasis:names:tc:[^:]:xmlns:.*
560 	nPos += rXMLNS.getLength();
561 	if( nPos >= nNameLen || rName[nPos] != ':' )
562 		return sal_False;
563 
564 	// :urn:oasis:names:tc:[^:]:xmlns:[^:]*:.*
565 	nPos = rName.indexOf( ':', nPos+1 );
566 	if( -1 == nPos )
567 		return sal_False;
568 
569 	// :urn:oasis:names:tc:[^:]:xmlns:[^:]*:[^:][^:][^:][^:]*
570 	sal_Int32 nVersionStart = nPos+1;
571 	if( nVersionStart+2 >= nNameLen ||
572 		-1 != rName.indexOf( ':', nVersionStart ) )
573 		return sal_False;
574 
575 	// :urn:oasis:names:tc:[^:]:xmlns:[^:]*:1\.[^:][^:]*
576 	if( rName[nVersionStart] != '1' || rName[nVersionStart+1] != '.' )
577 		return sal_False;
578 
579 	// replace [tcid] with current TCID and version with current version.
580 	OUStringBuffer aNewName( nNameLen +20 );
581 	aNewName.append( rName.copy( 0, nTCIdStart ) );
582 	aNewName.append( GetXMLToken( XML_OPENDOCUMENT ) );
583 	aNewName.append( rName.copy( nTCIdEnd, nVersionStart-nTCIdEnd ) );
584 	aNewName.append( GetXMLToken( XML_1_0 ) );
585 
586 	rName = aNewName.makeStringAndClear();
587 
588 	return sal_True;
589 }
590