Update git submodules
[LibreOffice.git] / xmlscript / source / xml_helper / xml_impctx.cxx
blob90fbfab61c841928e328ea34c0e6bc6c1faa884f
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <sal/config.h>
22 #include <xml_import.hxx>
24 #include <cppuhelper/implbase.hxx>
25 #include <cppuhelper/supportsservice.hxx>
26 #include <com/sun/star/container/NoSuchElementException.hpp>
27 #include <com/sun/star/xml/input/XAttributes.hpp>
28 #include <com/sun/star/lang/XInitialization.hpp>
29 #include <com/sun/star/uno/XComponentContext.hpp>
30 #include <com/sun/star/lang/XServiceInfo.hpp>
31 #include <sal/log.hxx>
33 #include <memory>
34 #include <mutex>
35 #include <optional>
36 #include <unordered_map>
37 #include <vector>
39 using namespace ::com::sun::star;
40 using namespace ::com::sun::star::uno;
42 namespace xmlscript
45 const sal_Int32 UID_UNKNOWN = -1;
47 typedef std::unordered_map< OUString, sal_Int32 > t_OUString2LongMap;
49 namespace {
51 struct PrefixEntry
53 ::std::vector< sal_Int32 > m_Uids;
55 PrefixEntry()
56 { m_Uids.reserve( 4 ); }
61 typedef std::unordered_map<
62 OUString, std::unique_ptr<PrefixEntry> > t_OUString2PrefixMap;
64 namespace {
66 struct ElementEntry
68 Reference< xml::input::XElement > m_xElement;
69 ::std::vector< OUString > m_prefixes;
71 ElementEntry()
72 { m_prefixes.reserve( 2 ); }
75 class ExtendedAttributes;
77 class MGuard
79 std::mutex * m_pMutex;
80 public:
81 explicit MGuard( std::optional<std::mutex> & oMutex )
82 : m_pMutex( oMutex ? &*oMutex : nullptr )
83 { if (m_pMutex) m_pMutex->lock(); }
84 ~MGuard() noexcept
85 { if (m_pMutex) m_pMutex->unlock(); }
88 class DocumentHandlerImpl :
89 public ::cppu::WeakImplHelper< xml::sax::XDocumentHandler,
90 xml::input::XNamespaceMapping,
91 lang::XInitialization,
92 css::lang::XServiceInfo >
94 friend class ExtendedAttributes;
96 Reference< xml::input::XRoot > m_xRoot;
98 t_OUString2LongMap m_URI2Uid;
99 sal_Int32 m_uid_count;
101 sal_Int32 m_nLastURI_lookup;
102 OUString m_aLastURI_lookup;
104 t_OUString2PrefixMap m_prefixes;
105 sal_Int32 m_nLastPrefix_lookup;
106 OUString m_aLastPrefix_lookup;
108 std::vector< ElementEntry > m_elements;
109 sal_Int32 m_nSkipElements;
111 mutable std::optional<std::mutex> m_oMutex;
113 inline Reference< xml::input::XElement > getCurrentElement() const;
115 inline sal_Int32 getUidByURI( OUString const & rURI );
116 inline sal_Int32 getUidByPrefix( OUString const & rPrefix );
118 inline void pushPrefix(
119 OUString const & rPrefix, OUString const & rURI );
120 inline void popPrefix( OUString const & rPrefix );
122 inline void getElementName(
123 OUString const & rQName, sal_Int32 * pUid, OUString * pLocalName );
125 public:
126 DocumentHandlerImpl(
127 Reference< xml::input::XRoot > const & xRoot,
128 bool bSingleThreadedUse );
130 // XServiceInfo
131 virtual OUString SAL_CALL getImplementationName() override;
132 virtual sal_Bool SAL_CALL supportsService(
133 OUString const & servicename ) override;
134 virtual Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
136 // XInitialization
137 virtual void SAL_CALL initialize(
138 Sequence< Any > const & arguments ) override;
140 // XDocumentHandler
141 virtual void SAL_CALL startDocument() override;
142 virtual void SAL_CALL endDocument() override;
143 virtual void SAL_CALL startElement(
144 OUString const & rQElementName,
145 Reference< xml::sax::XAttributeList > const & xAttribs ) override;
146 virtual void SAL_CALL endElement(
147 OUString const & rQElementName ) override;
148 virtual void SAL_CALL characters(
149 OUString const & rChars ) override;
150 virtual void SAL_CALL ignorableWhitespace(
151 OUString const & rWhitespaces ) override;
152 virtual void SAL_CALL processingInstruction(
153 OUString const & rTarget, OUString const & rData ) override;
154 virtual void SAL_CALL setDocumentLocator(
155 Reference< xml::sax::XLocator > const & xLocator ) override;
157 // XNamespaceMapping
158 virtual sal_Int32 SAL_CALL getUidByUri( OUString const & Uri ) override;
159 virtual OUString SAL_CALL getUriByUid( sal_Int32 Uid ) override;
164 constexpr OUString g_sXMLNS_PREFIX_UNKNOWN( u"<<< unknown prefix >>>"_ustr );
165 constexpr OUString g_sXMLNS( u"xmlns"_ustr );
168 DocumentHandlerImpl::DocumentHandlerImpl(
169 Reference< xml::input::XRoot > const & xRoot,
170 bool bSingleThreadedUse )
171 : m_xRoot( xRoot ),
172 m_uid_count( 0 ),
173 m_nLastURI_lookup( UID_UNKNOWN ),
174 m_aLastURI_lookup( u"<<< unknown URI >>>"_ustr ),
175 m_nLastPrefix_lookup( UID_UNKNOWN ),
176 m_aLastPrefix_lookup( u"<<< unknown URI >>>"_ustr ),
177 m_nSkipElements( 0 )
179 m_elements.reserve( 10 );
181 if (! bSingleThreadedUse)
182 m_oMutex.emplace();
185 inline Reference< xml::input::XElement >
186 DocumentHandlerImpl::getCurrentElement() const
188 MGuard aGuard( m_oMutex );
189 if (m_elements.empty())
190 return Reference< xml::input::XElement >();
191 else
192 return m_elements.back().m_xElement;
195 inline sal_Int32 DocumentHandlerImpl::getUidByURI( OUString const & rURI )
197 MGuard guard( m_oMutex );
198 if (m_nLastURI_lookup == UID_UNKNOWN || m_aLastURI_lookup != rURI)
200 t_OUString2LongMap::const_iterator iFind( m_URI2Uid.find( rURI ) );
201 if (iFind != m_URI2Uid.end()) // id found
203 m_nLastURI_lookup = iFind->second;
204 m_aLastURI_lookup = rURI;
206 else
208 m_nLastURI_lookup = m_uid_count;
209 ++m_uid_count;
210 m_URI2Uid[ rURI ] = m_nLastURI_lookup;
211 m_aLastURI_lookup = rURI;
214 return m_nLastURI_lookup;
217 inline sal_Int32 DocumentHandlerImpl::getUidByPrefix(
218 OUString const & rPrefix )
220 // commonly the last added prefix is used often for several tags...
221 // good guess
222 if (m_nLastPrefix_lookup == UID_UNKNOWN || m_aLastPrefix_lookup != rPrefix)
224 t_OUString2PrefixMap::const_iterator iFind(
225 m_prefixes.find( rPrefix ) );
226 if (iFind != m_prefixes.end())
228 const PrefixEntry & rPrefixEntry = *iFind->second;
229 SAL_WARN_IF( rPrefixEntry.m_Uids.empty(), "xmlscript.xmlhelper", "rPrefixEntry.m_Uids is empty" );
230 m_nLastPrefix_lookup = rPrefixEntry.m_Uids.back();
231 m_aLastPrefix_lookup = rPrefix;
233 else
235 m_nLastPrefix_lookup = UID_UNKNOWN;
236 m_aLastPrefix_lookup = g_sXMLNS_PREFIX_UNKNOWN;
239 return m_nLastPrefix_lookup;
242 inline void DocumentHandlerImpl::pushPrefix(
243 OUString const & rPrefix, OUString const & rURI )
245 // lookup id for URI
246 sal_Int32 nUid = getUidByURI( rURI );
248 // mark prefix with id
249 t_OUString2PrefixMap::const_iterator iFind( m_prefixes.find( rPrefix ) );
250 if (iFind == m_prefixes.end()) // unused prefix
252 PrefixEntry * pEntry = new PrefixEntry();
253 pEntry->m_Uids.push_back( nUid ); // latest id for prefix
254 m_prefixes[rPrefix].reset(pEntry);
256 else
258 PrefixEntry& rEntry = *iFind->second;
259 SAL_WARN_IF(rEntry.m_Uids.empty(), "xmlscript.xmlhelper", "pEntry->m_Uids is empty");
260 rEntry.m_Uids.push_back(nUid);
263 m_aLastPrefix_lookup = rPrefix;
264 m_nLastPrefix_lookup = nUid;
267 inline void DocumentHandlerImpl::popPrefix(
268 OUString const & rPrefix )
270 t_OUString2PrefixMap::iterator iFind( m_prefixes.find( rPrefix ) );
271 if (iFind != m_prefixes.end()) // unused prefix
273 PrefixEntry& rEntry = *iFind->second;
274 rEntry.m_Uids.pop_back(); // pop last id for prefix
275 if (rEntry.m_Uids.empty()) // erase prefix key
277 m_prefixes.erase(iFind);
281 m_nLastPrefix_lookup = UID_UNKNOWN;
282 m_aLastPrefix_lookup = g_sXMLNS_PREFIX_UNKNOWN;
285 inline void DocumentHandlerImpl::getElementName(
286 OUString const & rQName, sal_Int32 * pUid, OUString * pLocalName )
288 sal_Int32 nColonPos = rQName.indexOf( ':' );
289 *pLocalName = (nColonPos >= 0 ? rQName.copy( nColonPos +1 ) : rQName);
290 *pUid = getUidByPrefix(
291 nColonPos >= 0 ? rQName.copy( 0, nColonPos ) : OUString() );
294 namespace {
296 class ExtendedAttributes :
297 public ::cppu::WeakImplHelper< xml::input::XAttributes >
299 sal_Int32 const m_nAttributes;
300 std::unique_ptr<sal_Int32[]> m_pUids;
301 std::unique_ptr<OUString[]> m_pLocalNames;
302 std::unique_ptr<OUString[]> m_pQNames;
303 std::unique_ptr<OUString[]> m_pValues;
305 public:
306 inline ExtendedAttributes(
307 sal_Int32 nAttributes,
308 std::unique_ptr<sal_Int32[]> pUids,
309 std::unique_ptr<OUString[]> pLocalNames,
310 std::unique_ptr<OUString[]> pQNames,
311 Reference< xml::sax::XAttributeList > const & xAttributeList );
313 // XAttributes
314 virtual sal_Int32 SAL_CALL getLength() override;
315 virtual sal_Int32 SAL_CALL getIndexByQName(
316 OUString const & rQName ) override;
317 virtual sal_Int32 SAL_CALL getIndexByUidName(
318 sal_Int32 nUid, OUString const & rLocalName ) override;
319 virtual OUString SAL_CALL getQNameByIndex(
320 sal_Int32 nIndex ) override;
321 virtual sal_Int32 SAL_CALL getUidByIndex(
322 sal_Int32 nIndex ) override;
323 virtual OUString SAL_CALL getLocalNameByIndex(
324 sal_Int32 nIndex ) override;
325 virtual OUString SAL_CALL getValueByIndex(
326 sal_Int32 nIndex ) override;
327 virtual OUString SAL_CALL getValueByUidName(
328 sal_Int32 nUid, OUString const & rLocalName ) override;
329 virtual OUString SAL_CALL getTypeByIndex(
330 sal_Int32 nIndex ) override;
335 inline ExtendedAttributes::ExtendedAttributes(
336 sal_Int32 nAttributes,
337 std::unique_ptr<sal_Int32[]> pUids,
338 std::unique_ptr<OUString[]> pLocalNames, std::unique_ptr<OUString[]> pQNames,
339 Reference< xml::sax::XAttributeList > const & xAttributeList )
340 : m_nAttributes( nAttributes )
341 , m_pUids( std::move(pUids) )
342 , m_pLocalNames( std::move(pLocalNames) )
343 , m_pQNames( std::move(pQNames) )
344 , m_pValues( new OUString[ nAttributes ] )
346 for ( sal_Int32 nPos = 0; nPos < nAttributes; ++nPos )
348 m_pValues[ nPos ] = xAttributeList->getValueByIndex( nPos );
352 // XServiceInfo
354 OUString DocumentHandlerImpl::getImplementationName()
356 return u"com.sun.star.comp.xml.input.SaxDocumentHandler"_ustr;
359 sal_Bool DocumentHandlerImpl::supportsService( OUString const & servicename )
361 return cppu::supportsService(this, servicename);
364 Sequence< OUString > DocumentHandlerImpl::getSupportedServiceNames()
366 return { u"com.sun.star.xml.input.SaxDocumentHandler"_ustr };
369 // XInitialization
371 void DocumentHandlerImpl::initialize(
372 Sequence< Any > const & arguments )
374 MGuard guard( m_oMutex );
375 Reference< xml::input::XRoot > xRoot;
376 if (arguments.getLength() != 1 ||
377 !(arguments[ 0 ] >>= xRoot) ||
378 !xRoot.is())
380 throw RuntimeException( u"missing root instance!"_ustr );
382 m_xRoot = std::move(xRoot);
385 // XNamespaceMapping
387 sal_Int32 DocumentHandlerImpl::getUidByUri( OUString const & Uri )
389 sal_Int32 uid = getUidByURI( Uri );
390 SAL_WARN_IF( uid == UID_UNKNOWN, "xmlscript.xmlhelper", "uid UNKNOWN");
391 return uid;
394 OUString DocumentHandlerImpl::getUriByUid( sal_Int32 Uid )
396 MGuard guard( m_oMutex );
397 for (const auto& rURIUid : m_URI2Uid)
399 if (rURIUid.second == Uid)
400 return rURIUid.first;
402 throw container::NoSuchElementException( u"no such xmlns uid!"_ustr , getXWeak() );
405 // XDocumentHandler
407 void DocumentHandlerImpl::startDocument()
409 m_xRoot->startDocument( static_cast< xml::input::XNamespaceMapping * >( this ) );
412 void DocumentHandlerImpl::endDocument()
414 m_xRoot->endDocument();
417 void DocumentHandlerImpl::startElement(
418 OUString const & rQElementName,
419 Reference< xml::sax::XAttributeList > const & xAttribs )
421 Reference< xml::input::XElement > xCurrentElement;
422 Reference< xml::input::XAttributes > xAttributes;
423 sal_Int32 nUid;
424 OUString aLocalName;
425 ElementEntry elementEntry;
427 { // guard start:
428 MGuard aGuard( m_oMutex );
429 // currently skipping elements and waiting for end tags?
430 if (m_nSkipElements > 0)
432 ++m_nSkipElements; // wait for another end tag
433 SAL_INFO("xmlscript.xmlhelper", " no context given on createChildElement() => ignoring element \"" << rQElementName << "\" ...");
434 return;
437 sal_Int16 nAttribs = xAttribs->getLength();
439 // save all namespace ids
440 std::unique_ptr<sal_Int32[]> pUids(new sal_Int32[ nAttribs ]);
441 std::unique_ptr<OUString[]> pPrefixes(new OUString[ nAttribs ]);
442 std::unique_ptr<OUString[]> pLocalNames(new OUString[ nAttribs ]);
443 std::unique_ptr<OUString[]> pQNames(new OUString[ nAttribs ]);
445 // first recognize all xmlns attributes
446 sal_Int16 nPos;
447 for ( nPos = 0; nPos < nAttribs; ++nPos )
449 // mark attribute to be collected further
450 // on with attribute's uid and current prefix
451 pUids[ nPos ] = 0; // modified
453 pQNames[ nPos ] = xAttribs->getNameByIndex( nPos );
454 OUString const & rQAttributeName = pQNames[ nPos ];
456 if (rQAttributeName.startsWith( g_sXMLNS ))
458 if (rQAttributeName.getLength() == 5) // set default namespace
460 OUString aDefNamespacePrefix;
461 pushPrefix(
462 aDefNamespacePrefix,
463 xAttribs->getValueByIndex( nPos ) );
464 elementEntry.m_prefixes.push_back( aDefNamespacePrefix );
465 pUids[ nPos ] = UID_UNKNOWN;
466 pPrefixes[ nPos ] = g_sXMLNS;
467 pLocalNames[ nPos ] = aDefNamespacePrefix;
469 else if (':' == rQAttributeName[ 5 ]) // set prefix
471 OUString aPrefix( rQAttributeName.copy( 6 ) );
472 pushPrefix( aPrefix, xAttribs->getValueByIndex( nPos ) );
473 elementEntry.m_prefixes.push_back( aPrefix );
474 pUids[ nPos ] = UID_UNKNOWN;
475 pPrefixes[ nPos ] = g_sXMLNS;
476 pLocalNames[ nPos ] = aPrefix;
478 // else just a name starting with xmlns, but no prefix
482 // now read out attribute prefixes (all namespace prefixes have been set)
483 for ( nPos = 0; nPos < nAttribs; ++nPos )
485 if (pUids[ nPos ] >= 0) // no xmlns: attribute
487 OUString const & rQAttributeName = pQNames[ nPos ];
488 SAL_WARN_IF(rQAttributeName.startsWith( "xmlns:" ), "xmlscript.xmlhelper", "### unexpected xmlns!" );
490 // collect attribute's uid and current prefix
491 sal_Int32 nColonPos = rQAttributeName.indexOf( ':' );
492 if (nColonPos >= 0)
494 pPrefixes[ nPos ] = rQAttributeName.copy( 0, nColonPos );
495 pLocalNames[ nPos ] = rQAttributeName.copy( nColonPos +1 );
497 else
499 pPrefixes[ nPos ].clear();
500 pLocalNames[ nPos ] = rQAttributeName;
501 // leave local names unmodified
503 pUids[ nPos ] = getUidByPrefix( pPrefixes[ nPos ] );
506 pPrefixes.reset();
507 // ownership of arrays belongs to attribute list
508 xAttributes = new ExtendedAttributes(nAttribs, std::move(pUids), std::move(pLocalNames),
509 std::move(pQNames), xAttribs);
511 getElementName( rQElementName, &nUid, &aLocalName );
513 // create new child context and append to list
514 if (! m_elements.empty())
515 xCurrentElement = m_elements.back().m_xElement;
516 } // :guard end
518 if (xCurrentElement.is())
520 elementEntry.m_xElement =
521 xCurrentElement->startChildElement( nUid, aLocalName, xAttributes );
523 else
525 elementEntry.m_xElement =
526 m_xRoot->startRootElement( nUid, aLocalName, xAttributes );
530 MGuard aGuard( m_oMutex );
531 if (elementEntry.m_xElement.is())
533 m_elements.push_back( std::move(elementEntry) );
535 else
537 ++m_nSkipElements;
539 // pop prefixes
540 for (sal_Int32 nPos = elementEntry.m_prefixes.size(); nPos--;)
541 popPrefix(elementEntry.m_prefixes[nPos]);
543 SAL_INFO("xmlscript.xmlhelper", " no context given on createChildElement() => ignoring element \"" << rQElementName << "\" ...");
548 void DocumentHandlerImpl::endElement(
549 OUString const & rQElementName )
551 Reference< xml::input::XElement > xCurrentElement;
553 MGuard aGuard( m_oMutex );
554 if (m_nSkipElements)
556 --m_nSkipElements;
557 SAL_INFO("xmlscript.xmlhelper", "### received endElement() for \"" << rQElementName << "\".");
558 return;
561 // popping context
562 SAL_WARN_IF( m_elements.empty(), "xmlscript.xmlhelper", "m_elements is empty" );
563 ElementEntry& rEntry = m_elements.back();
564 xCurrentElement = rEntry.m_xElement;
566 #if OSL_DEBUG_LEVEL > 0
567 sal_Int32 nUid;
568 OUString aLocalName;
569 getElementName( rQElementName, &nUid, &aLocalName );
570 SAL_WARN_IF( xCurrentElement->getLocalName() != aLocalName, "xmlscript.xmlhelper", "xCurrentElement->getLocalName() != aLocalName" );
571 SAL_WARN_IF( xCurrentElement->getUid() != nUid, "xmlscript.xmlhelper", "xCurrentElement->getUid() != nUid" );
572 #endif
574 // pop prefixes
575 for ( sal_Int32 nPos = rEntry.m_prefixes.size(); nPos--; )
577 popPrefix( rEntry.m_prefixes[ nPos ] );
579 m_elements.pop_back();
581 xCurrentElement->endElement();
584 void DocumentHandlerImpl::characters( OUString const & rChars )
586 Reference< xml::input::XElement > xCurrentElement( getCurrentElement() );
587 if (xCurrentElement.is())
588 xCurrentElement->characters( rChars );
591 void DocumentHandlerImpl::ignorableWhitespace(
592 OUString const & rWhitespaces )
594 Reference< xml::input::XElement > xCurrentElement( getCurrentElement() );
595 if (xCurrentElement.is())
596 xCurrentElement->ignorableWhitespace( rWhitespaces );
599 void DocumentHandlerImpl::processingInstruction(
600 OUString const & rTarget, OUString const & rData )
602 Reference< xml::input::XElement > xCurrentElement( getCurrentElement() );
603 if (xCurrentElement.is())
604 xCurrentElement->processingInstruction( rTarget, rData );
605 else
606 m_xRoot->processingInstruction( rTarget, rData );
609 void DocumentHandlerImpl::setDocumentLocator(
610 Reference< xml::sax::XLocator > const & xLocator )
612 m_xRoot->setDocumentLocator( xLocator );
615 // XAttributes
617 sal_Int32 ExtendedAttributes::getIndexByQName( OUString const & rQName )
619 for ( sal_Int32 nPos = m_nAttributes; nPos--; )
621 if (m_pQNames[ nPos ] == rQName)
623 return nPos;
626 return -1;
629 sal_Int32 ExtendedAttributes::getLength()
631 return m_nAttributes;
634 OUString ExtendedAttributes::getLocalNameByIndex( sal_Int32 nIndex )
636 if (nIndex < m_nAttributes)
637 return m_pLocalNames[ nIndex ];
638 else
639 return OUString();
642 OUString ExtendedAttributes::getQNameByIndex( sal_Int32 nIndex )
644 if (nIndex < m_nAttributes)
645 return m_pQNames[ nIndex ];
646 else
647 return OUString();
650 OUString ExtendedAttributes::getTypeByIndex( sal_Int32 nIndex )
652 SAL_WARN_IF( nIndex >= m_nAttributes , "xmlscript.xmlhelper", "nIndex is bigger then m_nAttributes");
653 return OUString(); // unsupported
656 OUString ExtendedAttributes::getValueByIndex( sal_Int32 nIndex )
658 if (nIndex < m_nAttributes)
659 return m_pValues[ nIndex ];
660 else
661 return OUString();
664 sal_Int32 ExtendedAttributes::getIndexByUidName(
665 sal_Int32 nUid, OUString const & rLocalName )
667 for ( sal_Int32 nPos = m_nAttributes; nPos--; )
669 if (m_pUids[ nPos ] == nUid && m_pLocalNames[ nPos ] == rLocalName)
671 return nPos;
674 return -1;
677 sal_Int32 ExtendedAttributes::getUidByIndex( sal_Int32 nIndex )
679 if (nIndex < m_nAttributes)
680 return m_pUids[ nIndex ];
681 else
682 return -1;
685 OUString ExtendedAttributes::getValueByUidName(
686 sal_Int32 nUid, OUString const & rLocalName )
688 for ( sal_Int32 nPos = m_nAttributes; nPos--; )
690 if (m_pUids[ nPos ] == nUid && m_pLocalNames[ nPos ] == rLocalName)
692 return m_pValues[ nPos ];
695 return OUString();
698 Reference< xml::sax::XDocumentHandler > createDocumentHandler(
699 Reference< xml::input::XRoot > const & xRoot )
701 SAL_WARN_IF( !xRoot.is(), "xmlscript.xmlhelper", "xRoot is NULL" );
702 if (xRoot.is())
704 return new DocumentHandlerImpl(xRoot, true /* mt use */);
706 return Reference< xml::sax::XDocumentHandler >();
711 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
712 com_sun_star_comp_xml_input_SaxDocumentHandler_get_implementation(
713 css::uno::XComponentContext* , css::uno::Sequence<css::uno::Any> const& )
715 return cppu::acquire(new xmlscript::DocumentHandlerImpl({}, false /* mt use */));
718 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */