1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 /* 3 * This file is part of the LibreOffice project. 4 * 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/. 8 */ 9 10 #include <tools/stream.hxx> 11 #include <tools/XmlWalker.hxx> 12 13 #include <libxml/tree.h> 14 #include <libxml/parser.h> 15 #include <libxml/xmlstring.h> 16 #include <vector> 17 18 namespace tools 19 { 20 struct XmlWalkerImpl 21 { XmlWalkerImpltools::XmlWalkerImpl22 XmlWalkerImpl() 23 : mpDocPtr(nullptr) 24 , mpRoot(nullptr) 25 , mpCurrent(nullptr) 26 { 27 } 28 29 xmlDocPtr mpDocPtr; 30 xmlNodePtr mpRoot; 31 xmlNodePtr mpCurrent; 32 33 std::vector<xmlNodePtr> mpStack; 34 }; 35 XmlWalker()36XmlWalker::XmlWalker() 37 : mpImpl(std::make_unique<XmlWalkerImpl>()) 38 { 39 } 40 ~XmlWalker()41XmlWalker::~XmlWalker() 42 { 43 if (mpImpl) 44 xmlFreeDoc(mpImpl->mpDocPtr); 45 } 46 open(SvStream * pStream)47bool XmlWalker::open(SvStream* pStream) 48 { 49 std::size_t nSize = pStream->remainingSize(); 50 std::vector<sal_uInt8> aBuffer(nSize + 1); 51 pStream->ReadBytes(aBuffer.data(), nSize); 52 aBuffer[nSize] = 0; 53 mpImpl->mpDocPtr = xmlParseDoc(reinterpret_cast<xmlChar*>(aBuffer.data())); 54 if (mpImpl->mpDocPtr == nullptr) 55 return false; 56 mpImpl->mpRoot = xmlDocGetRootElement(mpImpl->mpDocPtr); 57 mpImpl->mpCurrent = mpImpl->mpRoot; 58 mpImpl->mpStack.push_back(mpImpl->mpCurrent); 59 return true; 60 } 61 name()62OString XmlWalker::name() { return reinterpret_cast<const char*>(mpImpl->mpCurrent->name); } 63 namespaceHref()64OString XmlWalker::namespaceHref() 65 { 66 return reinterpret_cast<const char*>(mpImpl->mpCurrent->ns->href); 67 } 68 namespacePrefix()69OString XmlWalker::namespacePrefix() 70 { 71 return reinterpret_cast<const char*>(mpImpl->mpCurrent->ns->prefix); 72 } 73 content()74OString XmlWalker::content() 75 { 76 OString aContent; 77 if (mpImpl->mpCurrent->xmlChildrenNode != nullptr) 78 { 79 xmlChar* pContent 80 = xmlNodeListGetString(mpImpl->mpDocPtr, mpImpl->mpCurrent->xmlChildrenNode, 1); 81 aContent = OString(reinterpret_cast<const char*>(pContent)); 82 xmlFree(pContent); 83 } 84 return aContent; 85 } 86 children()87void XmlWalker::children() 88 { 89 mpImpl->mpStack.push_back(mpImpl->mpCurrent); 90 mpImpl->mpCurrent = mpImpl->mpCurrent->xmlChildrenNode; 91 } 92 parent()93void XmlWalker::parent() 94 { 95 mpImpl->mpCurrent = mpImpl->mpStack.back(); 96 mpImpl->mpStack.pop_back(); 97 } 98 attribute(const OString & sName)99OString XmlWalker::attribute(const OString& sName) 100 { 101 xmlChar* xmlName = xmlCharStrdup(sName.getStr()); 102 xmlChar* xmlAttribute = xmlGetProp(mpImpl->mpCurrent, xmlName); 103 OString aAttributeContent( 104 xmlAttribute == nullptr ? "" : reinterpret_cast<const char*>(xmlAttribute)); 105 xmlFree(xmlAttribute); 106 xmlFree(xmlName); 107 108 return aAttributeContent; 109 } 110 next()111void XmlWalker::next() { mpImpl->mpCurrent = mpImpl->mpCurrent->next; } 112 isValid() const113bool XmlWalker::isValid() const { return mpImpl->mpCurrent != nullptr; } 114 115 } // end tools namespace 116 117 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 118