123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718 |
- #pragma once
- #include <library/cpp/string_utils/ztstrbuf/ztstrbuf.h>
- #include <util/generic/string.h>
- #include <util/generic/vector.h>
- #include <util/stream/output.h>
- #include <util/stream/str.h>
- #include <algorithm>
- #include "libxml-guards.h"
- namespace NXml {
- class TNode;
- class TConstNodes;
- class TConstNode;
- using TXPathContext = xmlXPathContext;
- class TDocument {
- public:
- enum Source {
- File,
- String,
- RootName,
- };
- public:
- /**
- * create TDocument
- * @param source: filename, XML string, or name for the root element (depends on @src)
- * @param src: source type: File | String | RootName
- * throws if file not found or cannot be parsed
- */
- TDocument(const TString& source, Source type = File);
- public:
- TDocument(const TDocument& that) = delete;
- TDocument& operator=(const TDocument& that) = delete;
- TDocument(TDocument&& that);
- TDocument& operator=(TDocument&& that);
- /**
- * get root element
- */
- TNode Root();
- TConstNode Root() const;
- void Save(IOutputStream& stream, TZtStringBuf enc = "", bool shouldFormat = true) const {
- int bufferSize = 0;
- xmlChar* xmlBuff = nullptr;
- const char* encoding = enc.size() ? enc.data() : Doc->encoding ? nullptr : "UTF-8";
- xmlDocDumpFormatMemoryEnc(Doc.Get(), &xmlBuff, &bufferSize, encoding, shouldFormat);
- TCharPtr xmlCharBuffPtr(xmlBuff);
- stream.Write(xmlBuff, bufferSize);
- }
- TString ToString(TZtStringBuf enc = "", bool shouldFormat = true) const {
- TStringStream s;
- Save(s, enc, shouldFormat);
- return s.Str();
- }
- void Swap(TDocument& that) {
- std::swap(this->Doc, that.Doc);
- }
- xmlDocPtr GetImpl() {
- return Doc.Get();
- }
- private:
- void ParseFile(const TString& file);
- void ParseString(TZtStringBuf xml);
- TDocument(TDocHolder doc)
- : Doc(std::move(doc))
- {
- }
- TDocHolder Doc;
- };
- struct TNamespaceForXPath {
- TString Prefix;
- TString Url;
- };
- typedef TVector<TNamespaceForXPath> TNamespacesForXPath;
- class TConstNodes {
- private:
- struct TConstNodesRef {
- explicit TConstNodesRef(TConstNodes& n)
- : r_(n)
- {
- }
- TConstNodes& r_;
- };
- public:
- TConstNodes(const TConstNodes& nodes);
- TConstNodes& operator=(const TConstNodes& nodes);
- TConstNodes(TConstNodesRef ref);
- TConstNodes& operator=(TConstNodesRef ref);
- operator TConstNodesRef();
- /**
- * get node by id
- * @param number: node id
- */
- TConstNode operator[](size_t number) const;
- /**
- * get number of nodes
- */
- size_t Size() const {
- return SizeValue;
- }
- size_t size() const {
- return SizeValue;
- }
- struct TNodeIter {
- const TConstNodes& Nodes;
- size_t Index;
- TConstNode operator*() const;
- bool operator==(const TNodeIter& other) const {
- return Index == other.Index;
- }
- bool operator!=(const TNodeIter& other) const {
- return !(*this == other);
- }
- TNodeIter operator++() {
- Index++;
- return *this;
- }
- };
- TNodeIter begin() const {
- return TNodeIter{*this, 0};
- }
- TNodeIter end() const {
- return TNodeIter{*this, size()};
- }
- private:
- friend class TDocument;
- friend class TConstNode;
- friend class TNode;
- TConstNodes(xmlDoc* doc, TXPathObjectPtr obj);
- size_t SizeValue;
- xmlDoc* Doc;
- TXPathObjectPtr Obj;
- };
- class TNode {
- public:
- friend class TDocument;
- friend class TConstNode;
- friend class TTextReader;
- /**
- * check if node is null
- */
- bool IsNull() const;
- /**
- * check if node is element node
- */
- bool IsElementNode() const;
- /**
- * Create xpath context to be used later for fast xpath evaluation.
- * @param nss: explicitly specify XML namespaces to use and their prefixes
- *
- * For better performance, when you need to evaluate several xpath expressions,
- * it makes sense to create a context, load namespace prefixes once
- * and use the context several times in Node(), Nodes(), XPath() function calls for several nodes.
- * The context may be used with any node of the current document, but
- * cannot be shared between different XML documents.
- */
- TXPathContextPtr CreateXPathContext(const TNamespacesForXPath& nss = TNamespacesForXPath()) const;
- /**
- * get all element nodes matching given xpath expression
- * @param xpath: xpath expression
- * @param quiet: don't throw exception if zero nodes found
- * @param ns: explicitly specify XML namespaces to use and their prefixes
- *
- * For historical reasons, this only works for *element* nodes.
- * Use the XPath function if you need other kinds of nodes.
- */
- TConstNodes Nodes(TZtStringBuf xpath, bool quiet = false, const TNamespacesForXPath& ns = TNamespacesForXPath()) const;
- /**
- * get all element nodes matching given xpath expression
- * @param xpath: xpath expression
- * @param quiet: don't throw exception if zero nodes found
- * @param ctxt: reusable xpath context
- *
- * For historical reasons, this only works for *element* nodes.
- * Use the XPath function if you need other kinds of nodes.
- */
- TConstNodes Nodes(TZtStringBuf xpath, bool quiet, TXPathContext& ctxt) const;
- /**
- * get all nodes matching given xpath expression
- * @param xpath: xpath expression
- * @param quiet: don't throw exception if zero nodes found
- * @param ns: explicitly specify XML namespaces to use and their prefixes
- */
- TConstNodes XPath(TZtStringBuf xpath, bool quiet = false, const TNamespacesForXPath& ns = TNamespacesForXPath()) const;
- /**
- * get all nodes matching given xpath expression
- * @param xpath: xpath expression
- * @param quiet: don't throw exception if zero nodes found
- * @param ctxt: reusable xpath context
- */
- TConstNodes XPath(TZtStringBuf xpath, bool quiet, TXPathContext& ctxt) const;
- /**
- * get the first element node matching given xpath expression
- * @param xpath: path to node (from current node)
- * @param quiet: don't throw exception if node not found,
- * return null node (@see IsNull())
- * @param ns: explicitly specify XML namespaces to use and their prefixes
- *
- * For historical reasons, this only works for *element* nodes.
- * Use the XPath function if you need other kinds of nodes.
- */
- /// @todo: quiet should be default, empty nodeset is not an error
- TNode Node(TZtStringBuf xpath, bool quiet = false, const TNamespacesForXPath& ns = TNamespacesForXPath());
- TConstNode Node(TZtStringBuf xpath, bool quiet = false, const TNamespacesForXPath& ns = TNamespacesForXPath()) const;
- /**
- * get the first element node matching given xpath expression
- * @param xpath: path to node (from current node)
- * @param quiet: don't throw exception if node not found,
- * return null node (@see IsNull())
- * @param ctxt: reusable xpath context
- *
- * For historical reasons, this only works for *element* nodes.
- * Use the XPath function if you need other kinds of nodes.
- */
- TNode Node(TZtStringBuf xpath, bool quiet, TXPathContext& ctxt);
- TConstNode Node(TZtStringBuf xpath, bool quiet, TXPathContext& ctxt) const;
- /**
- * get node first child
- * @param name: child name
- * @note if name is empty, returns the first child node of type "element"
- * @note returns null node if no child found
- */
- TNode FirstChild(TZtStringBuf name);
- TConstNode FirstChild(TZtStringBuf name) const;
- TNode FirstChild();
- TConstNode FirstChild() const;
- /**
- * get parent node
- * throws exception if has no parent
- */
- TNode Parent();
- TConstNode Parent() const;
- /**
- * get node neighbour
- * @param name: neighbour name
- * @note if name is empty, returns the next sibling node of type "element"
- * @node returns null node if no neighbour found
- */
- TNode NextSibling(TZtStringBuf name);
- TConstNode NextSibling(TZtStringBuf name) const;
- TNode NextSibling();
- TConstNode NextSibling() const;
- /**
- * create child node
- * @param name: child name
- * returns new empty node
- */
- TNode AddChild(TZtStringBuf name);
- /**
- * create child node with given value
- * @param name: child name
- * @param value: node value
- */
- template <class T>
- typename std::enable_if<!std::is_convertible_v<T, TZtStringBuf>, TNode>::type
- AddChild(TZtStringBuf name, const T& value);
- TNode AddChild(TZtStringBuf name, TZtStringBuf value);
- /**
- * add child node, making recursive copy of original
- * @param node: node to copy from
- * returns added node
- */
- TNode AddChild(const TConstNode& node);
- /**
- * create text child node
- * @param name: child name
- * @param value: node value
- */
- template <class T>
- typename std::enable_if<!std::is_convertible_v<T, TStringBuf>, TNode>::type
- AddText(const T& value);
- TNode AddText(TStringBuf value);
- /**
- * get node attribute
- * @param name: attribute name
- * throws exception if attribute not found
- */
- template <class T>
- T Attr(TZtStringBuf name) const;
- /**
- * get node attribute
- * @param name: attribute name
- * returns default value if attribute not found
- */
- template <class T>
- T Attr(TZtStringBuf name, const T& defvalue) const;
- /**
- * get node attribute
- * @param name: attribute name
- * @param value: return-value
- * throws exception if attribute not found
- */
- template <class T>
- void Attr(TZtStringBuf name, T& value) const;
- /**
- * get node attribute
- * @param name: attribute name
- * @param defvalue: default value
- * @param value: return-value
- * returns default value if attribute not found, attr value otherwise
- */
- template <class T>
- void Attr(TZtStringBuf name, T& value, const T& defvalue) const;
- /**
- * get node value (text)
- * @throws exception if node is blank
- */
- template <class T>
- T Value() const;
- /**
- * get node value
- * @param defvalue: default value
- * returns default value if node is blank
- */
- template <class T>
- T Value(const T& defvalue) const;
- /**
- * set node value
- * @param value: new text value
- */
- template <class T>
- typename std::enable_if<!std::is_convertible_v<T, TStringBuf>, void>::type
- SetValue(const T& value);
- void SetValue(TStringBuf value);
- /**
- * set/reset node attribute value,
- * if attribute does not exist, it'll be created
- * @param name: attribute name
- * @param value: attribute value
- */
- template<class T>
- typename std::enable_if<!std::is_convertible_v<T, TZtStringBuf>, void>::type
- SetAttr(TZtStringBuf name, const T& value);
- void SetAttr(TZtStringBuf name, TZtStringBuf value);
- void SetAttr(TZtStringBuf name);
- /**
- * delete node attribute
- * @param name: attribute name
- */
- void DelAttr(TZtStringBuf name);
- /**
- * set node application data
- * @param priv: new application data pointer
- */
- void SetPrivate(void* priv);
- /**
- * @return application data pointer, passed by SetPrivate
- */
- void* GetPrivate() const;
- /**
- * get node name
- */
- TString Name() const;
- /**
- * get node xpath
- */
- TString Path() const;
- /**
- * get node xml representation
- */
- TString ToString(TZtStringBuf enc = "") const {
- TStringStream s;
- Save(s, enc);
- return s.Str();
- }
- void Save(IOutputStream& stream, TZtStringBuf enc = "", bool shouldFormat = false) const;
- void SaveAsHtml(IOutputStream& stream, TZtStringBuf enc = "", bool shouldFormat = false) const;
- /**
- * get pointer to internal node
- */
- xmlNode* GetPtr();
- const xmlNode* GetPtr() const;
- /**
- * check if node is text-only node
- */
- bool IsText() const;
- /**
- * unlink node from parent and free
- */
- void Remove();
- /**
- * constructs null node
- */
- TNode()
- : NodePointer(nullptr)
- , DocPointer(nullptr)
- {
- }
- private:
- friend class TConstNodes;
- TNode(xmlDoc* doc, xmlNode* node)
- : NodePointer(node)
- , DocPointer(doc)
- {
- }
- TNode Find(xmlNode* start, TZtStringBuf name);
- template <class T>
- void AttrInternal(TCharPtr& value, T& res, TStringBuf errContext) const;
- void SaveInternal(IOutputStream& stream, TZtStringBuf enc, int options) const;
- xmlNode* NodePointer;
- xmlDoc* DocPointer;
- };
- class TConstNode {
- public:
- friend class TDocument;
- friend class TConstNodes;
- friend class TNode;
- /**
- * check if node is null
- */
- bool IsNull() const {
- return ActualNode.IsNull();
- }
- bool IsElementNode() const {
- return ActualNode.IsElementNode();
- }
- TConstNode Parent() const {
- return ActualNode.Parent();
- }
- /**
- * Create xpath context to be used later for fast xpath evaluation.
- * @param nss: explicitly specify XML namespaces to use and their prefixes
- */
- TXPathContextPtr CreateXPathContext(const TNamespacesForXPath& nss = TNamespacesForXPath()) const {
- return ActualNode.CreateXPathContext(nss);
- }
- /**
- * get all element nodes matching given xpath expression
- * @param xpath: xpath expression
- * @param quiet: don't throw exception if zero nodes found
- * @param ns: explicitly specify XML namespaces to use and their prefixes
- *
- * For historical reasons, this only works for *element* nodes.
- * Use the XPath function if you need other kinds of nodes.
- */
- TConstNodes Nodes(TZtStringBuf xpath, bool quiet = false, const TNamespacesForXPath& ns = TNamespacesForXPath()) const {
- return ActualNode.Nodes(xpath, quiet, ns);
- }
- /**
- * get all element nodes matching given xpath expression
- * @param xpath: xpath expression
- * @param quiet: don't throw exception if zero nodes found
- * @param ctxt: reusable xpath context
- *
- * For historical reasons, this only works for *element* nodes.
- * Use the XPath function if you need other kinds of nodes.
- */
- TConstNodes Nodes(TZtStringBuf xpath, bool quiet, TXPathContext& ctxt) const {
- return ActualNode.Nodes(xpath, quiet, ctxt);
- }
- /**
- * get all nodes matching given xpath expression
- * @param xpath: xpath expression
- * @param quiet: don't throw exception if zero nodes found
- * @param ns: explicitly specify XML namespaces to use and their prefixes
- */
- TConstNodes XPath(TZtStringBuf xpath, bool quiet = false, const TNamespacesForXPath& ns = TNamespacesForXPath()) const {
- return ActualNode.XPath(xpath, quiet, ns);
- }
- /**
- * get all nodes matching given xpath expression
- * @param xpath: xpath expression
- * @param quiet: don't throw exception if zero nodes found
- * @param ctxt: reusable xpath context
- */
- TConstNodes XPath(TZtStringBuf xpath, bool quiet, TXPathContext& ctxt) const {
- return ActualNode.XPath(xpath, quiet, ctxt);
- }
- /**
- * get the first element node matching given xpath expression
- * @param xpath: path to node (from current node)
- * @param quiet: don't throw exception if node not found,
- * return null node (@see IsNull())
- * @param ns: explicitly specify XML namespaces to use and their prefixes
- *
- * For historical reasons, this only works for *element* nodes.
- * Use the XPath function if you need other kinds of nodes.
- */
- TConstNode Node(TZtStringBuf xpath, bool quiet = false, const TNamespacesForXPath& ns = TNamespacesForXPath()) const {
- return ActualNode.Node(xpath, quiet, ns);
- }
- /**
- * get the first element node matching given xpath expression
- * @param xpath: path to node (from current node)
- * @param quiet: don't throw exception if node not found,
- * return null node (@see IsNull())
- * @param ctxt: reusable xpath context
- *
- * For historical reasons, this only works for *element* nodes.
- * Use the XPath function if you need other kinds of nodes.
- */
- TConstNode Node(TZtStringBuf xpath, bool quiet, TXPathContext& ctxt) const {
- return ActualNode.Node(xpath, quiet, ctxt);
- }
- TConstNode FirstChild(TZtStringBuf name) const {
- return ActualNode.FirstChild(name);
- }
- TConstNode FirstChild() const {
- return ActualNode.FirstChild();
- }
- /**
- * get node neighbour
- * @param name: neighbour name
- * throws exception if no neighbour found
- */
- TConstNode NextSibling(TZtStringBuf name) const {
- return ActualNode.NextSibling(name);
- }
- TConstNode NextSibling() const {
- return ActualNode.NextSibling();
- }
- /**
- * get node attribute
- * @param name: attribute name
- * throws exception if attribute not found
- */
- template <class T>
- T Attr(TZtStringBuf name) const {
- return ActualNode.Attr<T>(name);
- }
- /**
- * get node attribute
- * @param name: attribute name
- * returns default value if attribute not found
- */
- template <class T>
- T Attr(TZtStringBuf name, const T& defvalue) const {
- return ActualNode.Attr(name, defvalue);
- }
- /**
- * get node attribute
- * @param name: attribute name
- * @param value: return-value
- * throws exception if attribute not found
- */
- template <class T>
- void Attr(TZtStringBuf name, T& value) const {
- return ActualNode.Attr(name, value);
- }
- /**
- * get node attribute
- * @param name: attribute name
- * @param defvalue: default value
- * @param value: return-value
- * returns default value if attribute not found, attr value otherwise
- */
- template <class T>
- void Attr(TZtStringBuf name, T& value, const T& defvalue) const {
- return ActualNode.Attr(name, value, defvalue);
- }
- /**
- * get node value (text)
- * @throws exception if node is blank
- */
- template <class T>
- T Value() const {
- return ActualNode.Value<T>();
- }
- /**
- * get node value
- * @param defvalue: default value
- * returns default value if node is blank
- */
- template <class T>
- T Value(const T& defvalue) const {
- return ActualNode.Value(defvalue);
- }
- /**
- * get node name
- */
- TString Name() const {
- return ActualNode.Name();
- }
- /**
- * @return application data pointer, passed by SetPrivate
- */
- void* GetPrivate() const {
- return ActualNode.GetPrivate();
- }
- /**
- * get pointer to internal node
- */
- const xmlNode* GetPtr() const {
- return ActualNode.GetPtr();
- }
- /**
- * check if node is text-only node
- */
- bool IsText() const {
- return ActualNode.IsText();
- }
- /**
- * get node xpath
- */
- TString Path() const {
- return ActualNode.Path();
- }
- /**
- * get node xml representation
- */
- TString ToString(TZtStringBuf enc = "") const {
- return ActualNode.ToString(enc);
- }
- TConstNode() = default;
- TConstNode(TNode node)
- : ActualNode(node)
- {
- }
- TNode ConstCast() const {
- return ActualNode;
- }
- private:
- TNode ActualNode;
- };
- }
|