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>
36#include <unordered_map>
62typedef std::unordered_map<
76class ExtendedAttributes;
82 explicit MGuard( std::optional<std::mutex> & oMutex )
83 :
m_pMutex( oMutex ? &*oMutex : nullptr )
89class DocumentHandlerImpl :
90 public ::cppu::WeakImplHelper< xml::sax::XDocumentHandler,
91 xml::input::XNamespaceMapping,
92 lang::XInitialization,
93 css::lang::XServiceInfo >
95 friend class ExtendedAttributes;
114 inline Reference< xml::input::XElement > getCurrentElement()
const;
116 inline sal_Int32 getUidByURI( OUString
const & rURI );
117 inline sal_Int32 getUidByPrefix( OUString
const & rPrefix );
119 inline void pushPrefix(
120 OUString
const & rPrefix, OUString
const & rURI );
121 inline void popPrefix( OUString
const & rPrefix );
123 inline void getElementName(
124 OUString
const & rQName, sal_Int32 * pUid, OUString * pLocalName );
128 Reference< xml::input::XRoot >
const & xRoot,
129 bool bSingleThreadedUse );
134 OUString
const & servicename )
override;
138 virtual void SAL_CALL initialize(
139 Sequence< Any >
const & arguments )
override;
142 virtual void SAL_CALL startDocument()
override;
143 virtual void SAL_CALL endDocument()
override;
144 virtual void SAL_CALL startElement(
145 OUString
const & rQElementName,
146 Reference< xml::sax::XAttributeList >
const & xAttribs )
override;
147 virtual void SAL_CALL endElement(
148 OUString
const & rQElementName )
override;
149 virtual void SAL_CALL characters(
150 OUString
const & rChars )
override;
151 virtual void SAL_CALL ignorableWhitespace(
152 OUString
const & rWhitespaces )
override;
153 virtual void SAL_CALL processingInstruction(
154 OUString
const & rTarget, OUString
const & rData )
override;
155 virtual void SAL_CALL setDocumentLocator(
156 Reference< xml::sax::XLocator >
const & xLocator )
override;
159 virtual sal_Int32 SAL_CALL getUidByUri( OUString
const & Uri )
override;
160 virtual OUString SAL_CALL getUriByUid( sal_Int32 Uid )
override;
169DocumentHandlerImpl::DocumentHandlerImpl(
170 Reference< xml::input::XRoot >
const & xRoot,
171 bool bSingleThreadedUse )
182 if (! bSingleThreadedUse)
186inline Reference< xml::input::XElement >
187DocumentHandlerImpl::getCurrentElement()
const
191 return Reference< xml::input::XElement >();
196inline sal_Int32 DocumentHandlerImpl::getUidByURI( OUString
const & rURI )
201 t_OUString2LongMap::const_iterator iFind(
m_URI2Uid.find( rURI ) );
218inline sal_Int32 DocumentHandlerImpl::getUidByPrefix(
219 OUString
const & rPrefix )
225 t_OUString2PrefixMap::const_iterator iFind(
229 const PrefixEntry & rPrefixEntry = *iFind->second;
230 SAL_WARN_IF( rPrefixEntry.m_Uids.empty(),
"xmlscript.xmlhelper",
"rPrefixEntry.m_Uids is empty" );
243inline void DocumentHandlerImpl::pushPrefix(
244 OUString
const & rPrefix, OUString
const & rURI )
247 sal_Int32 nUid = getUidByURI( rURI );
250 t_OUString2PrefixMap::const_iterator iFind(
m_prefixes.find( rPrefix ) );
253 PrefixEntry * pEntry =
new PrefixEntry();
254 pEntry->m_Uids.push_back( nUid );
259 PrefixEntry& rEntry = *iFind->second;
260 SAL_WARN_IF(rEntry.m_Uids.empty(),
"xmlscript.xmlhelper",
"pEntry->m_Uids is empty");
261 rEntry.m_Uids.push_back(nUid);
268inline void DocumentHandlerImpl::popPrefix(
269 OUString
const & rPrefix )
271 t_OUString2PrefixMap::iterator iFind(
m_prefixes.find( rPrefix ) );
274 PrefixEntry& rEntry = *iFind->second;
275 rEntry.m_Uids.pop_back();
276 if (rEntry.m_Uids.empty())
286inline void DocumentHandlerImpl::getElementName(
287 OUString
const & rQName, sal_Int32 * pUid, OUString * pLocalName )
289 sal_Int32 nColonPos = rQName.indexOf(
':' );
290 *pLocalName = (nColonPos >= 0 ? rQName.copy( nColonPos +1 ) : rQName);
291 *pUid = getUidByPrefix(
292 nColonPos >= 0 ? rQName.copy( 0, nColonPos ) : OUString() );
297class ExtendedAttributes :
298 public ::cppu::WeakImplHelper< xml::input::XAttributes >
307 inline ExtendedAttributes(
308 sal_Int32 nAttributes,
309 std::unique_ptr<sal_Int32[]> pUids,
310 std::unique_ptr<OUString[]> pLocalNames,
311 std::unique_ptr<OUString[]> pQNames,
312 Reference< xml::sax::XAttributeList >
const & xAttributeList );
315 virtual sal_Int32 SAL_CALL
getLength()
override;
316 virtual sal_Int32 SAL_CALL getIndexByQName(
317 OUString
const & rQName )
override;
318 virtual sal_Int32 SAL_CALL getIndexByUidName(
319 sal_Int32 nUid, OUString
const & rLocalName )
override;
320 virtual OUString SAL_CALL getQNameByIndex(
321 sal_Int32 nIndex )
override;
322 virtual sal_Int32 SAL_CALL getUidByIndex(
323 sal_Int32 nIndex )
override;
324 virtual OUString SAL_CALL getLocalNameByIndex(
325 sal_Int32 nIndex )
override;
326 virtual OUString SAL_CALL getValueByIndex(
327 sal_Int32 nIndex )
override;
328 virtual OUString SAL_CALL getValueByUidName(
329 sal_Int32 nUid, OUString
const & rLocalName )
override;
330 virtual OUString SAL_CALL getTypeByIndex(
331 sal_Int32 nIndex )
override;
336inline ExtendedAttributes::ExtendedAttributes(
337 sal_Int32 nAttributes,
338 std::unique_ptr<sal_Int32[]> pUids,
339 std::unique_ptr<OUString[]> pLocalNames, std::unique_ptr<OUString[]> pQNames,
340 Reference< xml::sax::XAttributeList >
const & xAttributeList )
355OUString DocumentHandlerImpl::getImplementationName()
357 return "com.sun.star.comp.xml.input.SaxDocumentHandler";
360sal_Bool DocumentHandlerImpl::supportsService( OUString
const & servicename )
365Sequence< OUString > DocumentHandlerImpl::getSupportedServiceNames()
367 return {
"com.sun.star.xml.input.SaxDocumentHandler" };
372void DocumentHandlerImpl::initialize(
373 Sequence< Any >
const & arguments )
376 Reference< xml::input::XRoot > xRoot;
377 if (arguments.getLength() != 1 ||
378 !(arguments[ 0 ] >>= xRoot) ||
388sal_Int32 DocumentHandlerImpl::getUidByUri( OUString
const & Uri )
390 sal_Int32 uid = getUidByURI( Uri );
395OUString DocumentHandlerImpl::getUriByUid( sal_Int32 Uid )
400 if (rURIUid.second == Uid)
401 return rURIUid.first;
403 throw container::NoSuchElementException(
"no such xmlns uid!" , getXWeak() );
408void DocumentHandlerImpl::startDocument()
410 m_xRoot->startDocument(
static_cast< xml::input::XNamespaceMapping *
>(
this ) );
413void DocumentHandlerImpl::endDocument()
418void DocumentHandlerImpl::startElement(
419 OUString
const & rQElementName,
420 Reference< xml::sax::XAttributeList >
const & xAttribs )
422 Reference< xml::input::XElement > xCurrentElement;
423 Reference< xml::input::XAttributes > xAttributes;
426 ElementEntry elementEntry;
434 SAL_INFO(
"xmlscript.xmlhelper",
" no context given on createChildElement() => ignoring element \"" << rQElementName <<
"\" ...");
438 sal_Int16 nAttribs = xAttribs->getLength();
441 std::unique_ptr<sal_Int32[]> pUids(
new sal_Int32[ nAttribs ]);
442 std::unique_ptr<OUString[]> pPrefixes(
new OUString[ nAttribs ]);
443 std::unique_ptr<OUString[]> pLocalNames(
new OUString[ nAttribs ]);
444 std::unique_ptr<OUString[]> pQNames(
new OUString[ nAttribs ]);
448 for ( nPos = 0;
nPos < nAttribs; ++
nPos )
454 pQNames[
nPos ] = xAttribs->getNameByIndex( nPos );
455 OUString
const & rQAttributeName = pQNames[
nPos ];
457 if (rQAttributeName.startsWith(
g_sXMLNS ))
459 if (rQAttributeName.getLength() == 5)
461 OUString aDefNamespacePrefix;
464 xAttribs->getValueByIndex( nPos ) );
465 elementEntry.m_prefixes.push_back( aDefNamespacePrefix );
468 pLocalNames[
nPos ] = aDefNamespacePrefix;
470 else if (
':' == rQAttributeName[ 5 ])
472 OUString aPrefix( rQAttributeName.copy( 6 ) );
473 pushPrefix( aPrefix, xAttribs->getValueByIndex( nPos ) );
474 elementEntry.m_prefixes.push_back( aPrefix );
477 pLocalNames[
nPos ] = aPrefix;
484 for ( nPos = 0;
nPos < nAttribs; ++
nPos )
486 if (pUids[ nPos ] >= 0)
488 OUString
const & rQAttributeName = pQNames[
nPos ];
489 SAL_WARN_IF(rQAttributeName.startsWith(
"xmlns:" ),
"xmlscript.xmlhelper",
"### unexpected xmlns!" );
492 sal_Int32 nColonPos = rQAttributeName.indexOf(
':' );
495 pPrefixes[
nPos ] = rQAttributeName.copy( 0, nColonPos );
496 pLocalNames[
nPos ] = rQAttributeName.copy( nColonPos +1 );
500 pPrefixes[
nPos ].clear();
501 pLocalNames[
nPos ] = rQAttributeName;
504 pUids[
nPos ] = getUidByPrefix( pPrefixes[ nPos ] );
509 xAttributes =
new ExtendedAttributes(nAttribs, std::move(pUids), std::move(pLocalNames),
510 std::move(pQNames), xAttribs);
512 getElementName( rQElementName, &nUid, &aLocalName );
516 xCurrentElement =
m_elements.back().m_xElement;
519 if (xCurrentElement.is())
521 elementEntry.m_xElement =
522 xCurrentElement->startChildElement( nUid, aLocalName, xAttributes );
526 elementEntry.m_xElement =
527 m_xRoot->startRootElement( nUid, aLocalName, xAttributes );
532 if (elementEntry.m_xElement.is())
534 m_elements.push_back( std::move(elementEntry) );
541 for (sal_Int32 nPos = elementEntry.m_prefixes.size(); nPos--;)
542 popPrefix(elementEntry.m_prefixes[nPos]);
544 SAL_INFO(
"xmlscript.xmlhelper",
" no context given on createChildElement() => ignoring element \"" << rQElementName <<
"\" ...");
549void DocumentHandlerImpl::endElement(
550 OUString
const & rQElementName )
552 Reference< xml::input::XElement > xCurrentElement;
558 SAL_INFO(
"xmlscript.xmlhelper",
"### received endElement() for \"" << rQElementName <<
"\".");
565 xCurrentElement = rEntry.m_xElement;
567#if OSL_DEBUG_LEVEL > 0
570 getElementName( rQElementName, &nUid, &aLocalName );
571 SAL_WARN_IF( xCurrentElement->getLocalName() != aLocalName,
"xmlscript.xmlhelper",
"xCurrentElement->getLocalName() != aLocalName" );
572 SAL_WARN_IF( xCurrentElement->getUid() != nUid,
"xmlscript.xmlhelper",
"xCurrentElement->getUid() != nUid" );
576 for ( sal_Int32 nPos = rEntry.m_prefixes.size(); nPos--; )
578 popPrefix( rEntry.m_prefixes[ nPos ] );
582 xCurrentElement->endElement();
585void DocumentHandlerImpl::characters( OUString
const & rChars )
587 Reference< xml::input::XElement > xCurrentElement( getCurrentElement() );
588 if (xCurrentElement.is())
589 xCurrentElement->characters( rChars );
592void DocumentHandlerImpl::ignorableWhitespace(
593 OUString
const & rWhitespaces )
595 Reference< xml::input::XElement > xCurrentElement( getCurrentElement() );
596 if (xCurrentElement.is())
597 xCurrentElement->ignorableWhitespace( rWhitespaces );
600void DocumentHandlerImpl::processingInstruction(
601 OUString
const & rTarget, OUString
const & rData )
603 Reference< xml::input::XElement > xCurrentElement( getCurrentElement() );
604 if (xCurrentElement.is())
605 xCurrentElement->processingInstruction( rTarget, rData );
607 m_xRoot->processingInstruction( rTarget, rData );
610void DocumentHandlerImpl::setDocumentLocator(
611 Reference< xml::sax::XLocator >
const & xLocator )
613 m_xRoot->setDocumentLocator( xLocator );
618sal_Int32 ExtendedAttributes::getIndexByQName( OUString
const & rQName )
630sal_Int32 ExtendedAttributes::getLength()
635OUString ExtendedAttributes::getLocalNameByIndex( sal_Int32 nIndex )
643OUString ExtendedAttributes::getQNameByIndex( sal_Int32 nIndex )
651OUString ExtendedAttributes::getTypeByIndex( sal_Int32 nIndex )
657OUString ExtendedAttributes::getValueByIndex( sal_Int32 nIndex )
665sal_Int32 ExtendedAttributes::getIndexByUidName(
666 sal_Int32 nUid, OUString
const & rLocalName )
678sal_Int32 ExtendedAttributes::getUidByIndex( sal_Int32 nIndex )
686OUString ExtendedAttributes::getValueByUidName(
687 sal_Int32 nUid, OUString
const & rLocalName )
700 Reference< xml::input::XRoot >
const & xRoot )
702 SAL_WARN_IF( !xRoot.is(),
"xmlscript.xmlhelper",
"xRoot is NULL" );
705 return new DocumentHandlerImpl(xRoot,
true );
707 return Reference< xml::sax::XDocumentHandler >();
712extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
714 css::uno::XComponentContext* , css::uno::Sequence<css::uno::Any>
const& )
716 return cppu::acquire(
new xmlscript::DocumentHandlerImpl({},
false ));
#define SAL_WARN_IF(condition, area, stream)
#define SAL_INFO(area, stream)
double getLength(const B2DPolygon &rCandidate)
css::uno::Sequence< OUString > getSupportedServiceNames()
OUString getImplementationName()
bool CPPUHELPER_DLLPUBLIC supportsService(css::lang::XServiceInfo *implementation, rtl::OUString const &name)
std::unordered_map< OUString, std::unique_ptr< PrefixEntry > > t_OUString2PrefixMap
const sal_Int32 UID_UNKNOWN
std::unordered_map< OUString, sal_Int32 > t_OUString2LongMap
constexpr OUStringLiteral g_sXMLNS(u"xmlns")
constexpr OUStringLiteral g_sXMLNS_PREFIX_UNKNOWN(u"<<< unknown prefix >>>")
Reference< xml::sax::XDocumentHandler > createDocumentHandler(Reference< xml::input::XRoot > const &xRoot)
Reference< xml::input::XElement > m_xElement
t_OUString2LongMap m_URI2Uid
::std::vector< sal_Int32 > m_Uids
std::vector< ElementEntry > m_elements
std::unique_ptr< OUString[]> m_pValues
sal_Int32 const m_nAttributes
std::unique_ptr< sal_Int32[]> m_pUids
std::unique_ptr< OUString[]> m_pLocalNames
std::unique_ptr< OUString[]> m_pQNames
OUString m_aLastURI_lookup
sal_Int32 m_nLastURI_lookup
std::optional< std::mutex > m_oMutex
::std::vector< OUString > m_prefixes
OUString m_aLastPrefix_lookup
sal_Int32 m_nLastPrefix_lookup
Reference< xml::input::XRoot > m_xRoot
SAL_DLLPUBLIC_EXPORT css::uno::XInterface * com_sun_star_comp_xml_input_SaxDocumentHandler_get_implementation(css::uno::XComponentContext *, css::uno::Sequence< css::uno::Any > const &)
sal_Int32 m_nSkipElements