123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319 |
- #include <library/cpp/testing/unittest/registar.h>
- #include <util/generic/map.h>
- #include "xml-document.h"
- Y_UNIT_TEST_SUITE(TestXmlDocument) {
- Y_UNIT_TEST(Iteration) {
- NXml::TDocument xml(
- "<?xml version=\"1.0\"?>\n"
- "<root>qq<a><b></b></a>ww<c></c></root>",
- NXml::TDocument::String);
- NXml::TConstNode root = xml.Root();
- UNIT_ASSERT_EQUAL(root.Name(), "root");
- NXml::TConstNode n = root.FirstChild().NextSibling();
- UNIT_ASSERT_EQUAL(n.Name(), "a");
- n = n.NextSibling().NextSibling();
- UNIT_ASSERT_EQUAL(n.Name(), "c");
- }
- Y_UNIT_TEST(ParseString) {
- NXml::TDocument xml(
- "<?xml version=\"1.0\"?>\n"
- "<root>\n"
- "<a><b len=\"15\" correct=\"1\">hello world</b></a>\n"
- "<text>Некоторый текст</text>\n"
- "</root>",
- NXml::TDocument::String);
- NXml::TConstNode root = xml.Root();
- NXml::TConstNode b = root.Node("a/b");
- UNIT_ASSERT_EQUAL(b.Attr<int>("len"), 15);
- UNIT_ASSERT_EQUAL(b.Attr<bool>("correct"), true);
- NXml::TConstNode text = root.Node("text");
- UNIT_ASSERT_EQUAL(text.Value<TString>(), "Некоторый текст");
- }
- Y_UNIT_TEST(SerializeString) {
- NXml::TDocument xml("frob", NXml::TDocument::RootName);
- xml.Root().SetAttr("xyzzy", "Frobozz");
- xml.Root().SetAttr("kulness", 0.3);
- xml.Root().SetAttr("timelimit", 3);
- NXml::TNode authors = xml.Root().AddChild("authors");
- authors.AddChild("graham").SetAttr("name", "Nelson");
- authors.AddChild("zarf").SetValue("Andrew Plotkin");
- authors.AddChild("emshort", "Emily Short");
- TString data = xml.ToString("utf-8");
- UNIT_ASSERT_EQUAL(data, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
- "<frob xyzzy=\"Frobozz\" kulness=\"0.3\" timelimit=\"3\">\n"
- " <authors>\n"
- " <graham name=\"Nelson\"/>\n"
- " <zarf>Andrew Plotkin</zarf>\n"
- " <emshort>Emily Short</emshort>\n"
- " </authors>\n"
- "</frob>\n");
- // check default utf8 output with ru
- {
- NXml::TDocument xml2("frob", NXml::TDocument::RootName);
- xml2.Root().SetAttr("xyzzy", "привет =)");
- UNIT_ASSERT_VALUES_EQUAL(xml2.ToString(), "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
- "<frob xyzzy=\"привет =)\"/>\n");
- }
- }
- Y_UNIT_TEST(XPathNs) {
- using namespace NXml;
- TDocument xml(
- "<?xml version=\"1.0\"?>\n"
- "<root xmlns='http://hello.com/hello'>\n"
- "<a><b len=\"15\" correct=\"1\">hello world</b></a>\n"
- "<text>Некоторый текст</text>\n"
- "</root>",
- TDocument::String);
- TNamespacesForXPath nss;
- TNamespaceForXPath ns = {"h", "http://hello.com/hello"};
- nss.push_back(ns);
- TConstNode root = xml.Root();
- TConstNode b = root.Node("h:a/h:b", false, nss);
- UNIT_ASSERT_EQUAL(b.Attr<int>("len"), 15);
- UNIT_ASSERT_EQUAL(b.Attr<bool>("correct"), true);
- TConstNode text = root.Node("h:text", false, nss);
- UNIT_ASSERT_EQUAL(text.Value<TString>(), "Некоторый текст");
- // For performance you can create xpath context once using nss and pass it.
- TXPathContextPtr ctxt = root.CreateXPathContext(nss);
- UNIT_ASSERT(root.Node("text", true, *ctxt).IsNull());
- UNIT_ASSERT_EXCEPTION(root.Node("text", false, *ctxt), yexception);
- UNIT_ASSERT_EQUAL(root.Node("h:text", false, *ctxt).Value<TString>(), "Некоторый текст");
- }
- Y_UNIT_TEST(XmlNodes) {
- using namespace NXml;
- TDocument xml("<?xml version=\"1.0\"?>\n"
- "<root>qq<a><b>asdfg</b></a>ww<c></c></root>",
- NXml::TDocument::String);
- TNode root = xml.Root();
- UNIT_ASSERT_EQUAL(root.Value<TString>(), "qqasdfgww");
- TConstNode node = root.FirstChild();
- UNIT_ASSERT_EQUAL(node.IsText(), true);
- UNIT_ASSERT_EQUAL(node.Value<TString>(), "qq");
- node = node.NextSibling();
- UNIT_ASSERT_EQUAL(node.IsText(), false);
- UNIT_ASSERT_EQUAL(node.Name(), "a");
- UNIT_ASSERT_EQUAL(node.Value<TString>(), "asdfg");
- node = node.NextSibling();
- UNIT_ASSERT_EQUAL(node.IsText(), true);
- UNIT_ASSERT_EQUAL(node.Value<TString>(), "ww");
- node = node.NextSibling();
- UNIT_ASSERT_EQUAL(node.IsText(), false);
- UNIT_ASSERT_EQUAL(node.Name(), "c");
- UNIT_ASSERT_EQUAL(node.Value<TString>(), "");
- node = node.NextSibling();
- UNIT_ASSERT_EQUAL(node.IsNull(), true);
- TStringStream iterLog;
- for (const auto& node2 : root.Nodes("/root/*")) {
- iterLog << node2.Name() << ';';
- }
- UNIT_ASSERT_STRINGS_EQUAL(iterLog.Str(), "a;c;");
- // get only element nodes, ignore text nodes with empty "name" param
- node = root.FirstChild(TString());
- UNIT_ASSERT_EQUAL(node.IsText(), false);
- UNIT_ASSERT_EQUAL(node.Name(), "a");
- node = node.NextSibling(TString());
- UNIT_ASSERT_EQUAL(node.IsText(), false);
- UNIT_ASSERT_EQUAL(node.Name(), "c");
- // use exact "name" to retrieve children and siblings
- node = root.FirstChild("a");
- UNIT_ASSERT_EQUAL(node.IsNull(), false);
- UNIT_ASSERT_EQUAL(node.Name(), "a");
- node = node.NextSibling("c");
- UNIT_ASSERT_EQUAL(node.IsNull(), false);
- UNIT_ASSERT_EQUAL(node.Name(), "c");
- node = root.FirstChild("c"); // skip "a"
- UNIT_ASSERT_EQUAL(node.IsNull(), false);
- UNIT_ASSERT_EQUAL(node.Name(), "c");
- // node not found: no exceptions, null nodes are returned
- node = root.FirstChild("b"); // b is not direct child of root
- UNIT_ASSERT_EQUAL(node.IsNull(), true);
- node = root.FirstChild("nosuchnode");
- UNIT_ASSERT_EQUAL(node.IsNull(), true);
- node = root.FirstChild();
- node = root.NextSibling("unknownnode");
- UNIT_ASSERT_EQUAL(node.IsNull(), true);
- UNIT_ASSERT_EXCEPTION(node.Name(), yexception);
- UNIT_ASSERT_EXCEPTION(node.Value<TString>(), yexception);
- UNIT_ASSERT_EXCEPTION(node.IsText(), yexception);
- }
- Y_UNIT_TEST(DefVal) {
- using namespace NXml;
- TDocument xml("<?xml version=\"1.0\"?>\n"
- "<root><a></a></root>",
- NXml::TDocument::String);
- UNIT_ASSERT_EQUAL(xml.Root().Node("a", true).Node("b", true).Value<int>(3), 3);
- }
- Y_UNIT_TEST(NodesVsXPath) {
- using namespace NXml;
- TDocument xml("<?xml version=\"1.0\"?>\n"
- "<root><a x=\"y\"></a></root>",
- NXml::TDocument::String);
- UNIT_ASSERT_EXCEPTION(xml.Root().Nodes("/root/a/@x"), yexception);
- UNIT_ASSERT_VALUES_EQUAL(xml.Root().XPath("/root/a/@x").Size(), 1);
- }
- Y_UNIT_TEST(NodeIsFirst) {
- using namespace NXml;
- TDocument xml("<?xml version=\"1.0\"?>\n"
- "<root><a x=\"y\">first</a>"
- "<a>second</a></root>",
- NXml::TDocument::String);
- UNIT_ASSERT_EXCEPTION(xml.Root().Node("/root/a/@x"), yexception);
- UNIT_ASSERT_STRINGS_EQUAL(xml.Root().Node("/root/a").Value<TString>(), "first");
- }
- Y_UNIT_TEST(CopyNode) {
- using namespace NXml;
- // default-construct empty node
- TNode empty;
- // put to container
- TMap<int, TNode> nmap;
- nmap[2];
- // do copy
- TDocument xml("<?xml version=\"1.0\"?>\n"
- "<root><a></a></root>",
- TDocument::String);
- TDocument xml2("<?xml version=\"1.0\"?>\n"
- "<root><node><b>bold</b><i>ita</i></node></root>",
- TDocument::String);
- TNode node = xml2.Root().Node("//node");
- TNode place = xml.Root().Node("//a");
- place.AddChild(node);
- TStringStream s;
- xml.Save(s, "", false);
- UNIT_ASSERT_VALUES_EQUAL(s.Str(),
- "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
- "<root><a><node><b>bold</b><i>ita</i></node></a></root>\n");
- }
- Y_UNIT_TEST(RenderNode) {
- using namespace NXml;
- {
- // no namespaces
- TDocument xml(
- "<?xml version=\"1.0\"?>\n"
- "<root>\n"
- "<a><b len=\"15\" correct=\"1\">hello world</b></a>\n"
- "<text>Некоторый текст</text>\n"
- "</root>",
- TDocument::String);
- TNode n = xml.Root().Node("//a");
- UNIT_ASSERT_VALUES_EQUAL(n.ToString(), "<a><b len=\"15\" correct=\"1\">hello world</b></a>");
- }
- {
- // namespaces
- TDocument xml(
- "<?xml version=\"1.0\"?>\n"
- "<root xmlns='http://hello.com/hello'>\n"
- "<a><b len=\"15\" correct=\"1\">hello world</b></a>\n"
- "<text>Некоторый текст</text>\n"
- "</root>",
- TDocument::String);
- TNamespacesForXPath nss;
- TNamespaceForXPath ns = {"h", "http://hello.com/hello"};
- nss.push_back(ns);
- TNode n = xml.Root().Node("//h:a", false, nss);
- UNIT_ASSERT_VALUES_EQUAL(n.ToString(), "<a><b len=\"15\" correct=\"1\">hello world</b></a>");
- }
- }
- Y_UNIT_TEST(ReuseXPathContext) {
- using namespace NXml;
- TDocument xml(
- "<?xml version=\"1.0\"?>\n"
- "<root>\n"
- "<a><b><c>Hello, world!</c></b></a>\n"
- "<text x=\"10\">First</text>\n"
- "<text y=\"20\">Second</text>\n"
- "</root>",
- TDocument::String);
- TXPathContextPtr rootCtxt = xml.Root().CreateXPathContext();
- // Check Node()
- TConstNode b = xml.Root().Node("a/b", false, *rootCtxt);
- // We can use root node context for xpath evaluation in any node
- TConstNode c1 = b.Node("c", false, *rootCtxt);
- UNIT_ASSERT_EQUAL(c1.Value<TString>(), "Hello, world!");
- TXPathContextPtr bCtxt = b.CreateXPathContext();
- TConstNode c2 = b.Node("c", false, *bCtxt);
- UNIT_ASSERT_EQUAL(c2.Value<TString>(), "Hello, world!");
- // Mixing contexts from different documents is forbidden
- TDocument otherXml("<root></root>", TDocument::String);
- TXPathContextPtr otherCtxt = otherXml.Root().CreateXPathContext();
- UNIT_ASSERT_EXCEPTION(b.Node("c", false, *otherCtxt), yexception);
- // Check Nodes()
- TConstNodes texts = xml.Root().Nodes("text", true, *rootCtxt);
- UNIT_ASSERT_EQUAL(texts.Size(), 2);
- // Nodes() does't work for non-element nodes
- UNIT_ASSERT_EXCEPTION(xml.Root().Nodes("text/@x", true, *rootCtxt), yexception);
- // Check XPath()
- TConstNodes ys = xml.Root().XPath("text/@y", true, *rootCtxt);
- UNIT_ASSERT_EQUAL(ys.Size(), 1);
- UNIT_ASSERT_EQUAL(ys[0].Value<int>(), 20);
- }
- Y_UNIT_TEST(Html) {
- using namespace NXml;
- TDocument htmlChunk("video", TDocument::RootName);
- TNode videoNode = htmlChunk.Root();
- videoNode.SetAttr("controls");
- TStringStream ss;
- videoNode.SaveAsHtml(ss);
- UNIT_ASSERT_EQUAL(ss.Str(), "<video controls></video>");
- }
- Y_UNIT_TEST(Move) {
- using namespace NXml;
- TDocument xml1("foo", TDocument::RootName);
- xml1.Root().AddChild("bar");
- UNIT_ASSERT_VALUES_EQUAL(xml1.Root().ToString(), "<foo><bar/></foo>");
- TDocument xml2 = std::move(xml1);
- UNIT_ASSERT_EXCEPTION(xml1.Root(), yexception);
- UNIT_ASSERT_VALUES_EQUAL(xml2.Root().ToString(), "<foo><bar/></foo>");
- }
- Y_UNIT_TEST(StringConversion) {
- using namespace NXml;
- TDocument xml("foo", TDocument::RootName);
- auto root = xml.Root();
- const TStringBuf stringBuf = "bar";
- root.SetAttr("bar", stringBuf);
- const TString tString = "baz";
- root.SetAttr("baz", tString);
- root.SetAttr("quux", "literal");
- root.SetAttr("frob", 500);
- }
- }
|