aboutsummaryrefslogtreecommitdiffstats
path: root/library/cpp/xml/document/node-attr.h
diff options
context:
space:
mode:
authorDevtools Arcadia <arcadia-devtools@yandex-team.ru>2022-02-07 18:08:42 +0300
committerDevtools Arcadia <arcadia-devtools@mous.vla.yp-c.yandex.net>2022-02-07 18:08:42 +0300
commit1110808a9d39d4b808aef724c861a2e1a38d2a69 (patch)
treee26c9fed0de5d9873cce7e00bc214573dc2195b7 /library/cpp/xml/document/node-attr.h
downloadydb-1110808a9d39d4b808aef724c861a2e1a38d2a69.tar.gz
intermediate changes
ref:cde9a383711a11544ce7e107a78147fb96cc4029
Diffstat (limited to 'library/cpp/xml/document/node-attr.h')
-rw-r--r--library/cpp/xml/document/node-attr.h209
1 files changed, 209 insertions, 0 deletions
diff --git a/library/cpp/xml/document/node-attr.h b/library/cpp/xml/document/node-attr.h
new file mode 100644
index 0000000000..6e74403943
--- /dev/null
+++ b/library/cpp/xml/document/node-attr.h
@@ -0,0 +1,209 @@
+#pragma once
+
+#include "xml-document-decl.h"
+#include "libxml-guards.h"
+#include <util/stream/str.h>
+#include <util/string/cast.h>
+
+namespace NXml {
+#define THROW(x, y) ythrow yexception() << #x << ": " << y
+
+ // libxml defines unsigned char -> xmlChar,
+ // and all functions use xmlChar.
+ inline static const char* CAST2CHAR(const xmlChar* x) {
+ return reinterpret_cast<const char*>(x);
+ }
+ inline static const xmlChar* XMLCHAR(const char* x) {
+ return reinterpret_cast<const xmlChar*>(x);
+ }
+
+ template <class T>
+ void TNode::AttrInternal(TCharPtr& value, T& res, TStringBuf errContext) const {
+ try {
+ res = FromString<T>(CAST2CHAR(value.Get()));
+ } catch (TFromStringException&) {
+ THROW(XmlException, "Failed to convert string " << TString{TStringBuf(CAST2CHAR(value.Get())).substr(0, 50)}.Quote() << " from '" << errContext << "' to requested type");
+ }
+ }
+
+ template <>
+ inline void TNode::AttrInternal(TCharPtr& value, TString& res, TStringBuf /*errContext*/) const {
+ TString tmp(CAST2CHAR(value.Get()));
+ res.swap(tmp);
+ }
+
+ template <class T>
+ T TNode::Attr(TZtStringBuf name) const {
+ TCharPtr value(xmlGetProp(NodePointer, XMLCHAR(name.c_str())));
+ if (!value) {
+ THROW(AttributeNotFound, Path() << "@" << name);
+ }
+
+ T t;
+ AttrInternal(value, t, name);
+ return t;
+ }
+
+ template <class T>
+ T TNode::Attr(TZtStringBuf name, const T& defvalue) const {
+ TCharPtr attr(xmlGetProp(NodePointer, XMLCHAR(name.c_str())));
+ if (!attr) {
+ return defvalue;
+ }
+
+ T t;
+ AttrInternal(attr, t, name);
+ return t;
+ }
+
+ template <class T>
+ void TNode::Attr(TZtStringBuf name, T& value) const {
+ TCharPtr attr(xmlGetProp(NodePointer, XMLCHAR(name.c_str())));
+ if (!attr) {
+ THROW(AttributeNotFound, Path() << name);
+ }
+
+ AttrInternal(attr, value, name);
+ }
+
+ template <class T>
+ void TNode::Attr(TZtStringBuf name, T& value, const T& defvalue) const {
+ TCharPtr attr(xmlGetProp(NodePointer, XMLCHAR(name.c_str())));
+
+ if (!attr) {
+ value = defvalue;
+ } else {
+ AttrInternal(attr, value, name);
+ }
+ }
+
+ template <class T>
+ T TNode::Value() const {
+ if (!NodePointer || xmlIsBlankNode(NodePointer)) {
+ THROW(NodeIsBlank, Path());
+ }
+
+ TCharPtr val(xmlNodeGetContent(NodePointer));
+ T t;
+ AttrInternal(val, t, this->Name());
+ return t;
+ }
+
+ template <class T>
+ T TNode::Value(const T& defvalue) const {
+ if (!NodePointer || xmlIsBlankNode(NodePointer)) {
+ return defvalue;
+ }
+
+ TCharPtr val(xmlNodeGetContent(NodePointer));
+ T t;
+ AttrInternal(val, t, this->Name());
+ return t;
+ }
+
+ template <class T>
+ typename std::enable_if<!std::is_convertible_v<T, TStringBuf>, void>::type
+ TNode::SetValue(const T& value) {
+ TStringStream ss;
+ ss << value;
+ SetValue(ss.Str());
+ }
+
+ inline void TNode::SetValue(TStringBuf value) {
+ xmlNodeSetContent(NodePointer, XMLCHAR(""));
+ xmlNodeAddContentLen(NodePointer, XMLCHAR(value.data()), value.Size());
+ }
+
+ inline void TNode::SetAttr(TZtStringBuf name, TZtStringBuf value) {
+ xmlAttr* attr = xmlSetProp(NodePointer, XMLCHAR(name.c_str()), XMLCHAR(value.c_str()));
+
+ if (!attr) {
+ THROW(XmlException, "Can't set node attribute <"
+ << name
+ << "> to <"
+ << value
+ << ">");
+ }
+ }
+
+ template <class T>
+ typename std::enable_if<!std::is_convertible_v<T, TZtStringBuf>, void>::type
+ TNode::SetAttr(TZtStringBuf name, const T& value) {
+ TStringStream ss;
+ ss << value;
+ SetAttr(name, TZtStringBuf(ss.Str()));
+ }
+
+ inline void TNode::SetAttr(TZtStringBuf name) {
+ xmlAttr* attr = xmlSetProp(NodePointer, XMLCHAR(name.c_str()), nullptr);
+
+ if (!attr) {
+ THROW(XmlException, "Can't set node empty attribute <"
+ << name
+ << ">");
+ }
+ }
+
+ inline void TNode::DelAttr(TZtStringBuf name) {
+ if (xmlUnsetProp(NodePointer, XMLCHAR(name.c_str())) < 0)
+ THROW(XmlException, "Can't delete node attribute <"
+ << name
+ << ">");
+ }
+
+ template <class T>
+ typename std::enable_if<!std::is_convertible_v<T, TZtStringBuf>, TNode>::type
+ TNode::AddChild(TZtStringBuf name, const T& value) {
+ TStringStream ss;
+ ss << value;
+ return AddChild(name, TZtStringBuf(ss.Str()));
+ }
+
+ inline TNode TNode::AddChild(TZtStringBuf name, TZtStringBuf value) {
+ if (IsNull()) {
+ THROW(XmlException, "addChild [name=" << name << ", value=" << value
+ << "]: can't add child to null node");
+ }
+
+ xmlNode* child = nullptr;
+
+ if (value.empty()) {
+ child = xmlNewTextChild(NodePointer, nullptr, XMLCHAR(name.c_str()), nullptr);
+ } else {
+ child = xmlNewTextChild(
+ NodePointer, nullptr, XMLCHAR(name.c_str()), XMLCHAR(value.c_str()));
+ }
+
+ if (!child) {
+ THROW(XmlException, "addChild [name=" << name << ", value=" << value
+ << "]: xmlNewTextChild returned NULL");
+ }
+
+ return TNode(DocPointer, child);
+ }
+
+ template <class T>
+ typename std::enable_if<!std::is_convertible_v<T, TStringBuf>, TNode>::type
+ TNode::AddText(const T& value) {
+ TStringStream ss;
+ ss << value;
+ return AddText(ss.Str());
+ }
+
+ inline TNode TNode::AddText(TStringBuf value) {
+ if (IsNull()) {
+ THROW(XmlException, "addChild [value=" << value
+ << "]: can't add child to null node");
+ }
+
+ xmlNode* child = xmlNewTextLen((xmlChar*)value.data(), value.size());
+ child = xmlAddChild(NodePointer, child);
+
+ if (!child) {
+ THROW(XmlException, "addChild [value=" << value
+ << "]: xmlNewTextChild returned NULL");
+ }
+
+ return TNode(DocPointer, child);
+ }
+}