diff options
author | Devtools Arcadia <arcadia-devtools@yandex-team.ru> | 2022-02-07 18:08:42 +0300 |
---|---|---|
committer | Devtools Arcadia <arcadia-devtools@mous.vla.yp-c.yandex.net> | 2022-02-07 18:08:42 +0300 |
commit | 1110808a9d39d4b808aef724c861a2e1a38d2a69 (patch) | |
tree | e26c9fed0de5d9873cce7e00bc214573dc2195b7 /library/cpp/xml/document/xml-document-decl.h | |
download | ydb-1110808a9d39d4b808aef724c861a2e1a38d2a69.tar.gz |
intermediate changes
ref:cde9a383711a11544ce7e107a78147fb96cc4029
Diffstat (limited to 'library/cpp/xml/document/xml-document-decl.h')
-rw-r--r-- | library/cpp/xml/document/xml-document-decl.h | 718 |
1 files changed, 718 insertions, 0 deletions
diff --git a/library/cpp/xml/document/xml-document-decl.h b/library/cpp/xml/document/xml-document-decl.h new file mode 100644 index 0000000000..bfda1fb7e6 --- /dev/null +++ b/library/cpp/xml/document/xml-document-decl.h @@ -0,0 +1,718 @@ +#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; + }; + +} |