static ElementIdentifier getElementIdentifier(Node * element) { NamedNodeMapPtr attrs = element->attributes(); std::vector<std::pair<std::string, std::string>> attrs_kv; for (size_t i = 0; i < attrs->length(); ++i) { Node * node = attrs->item(i); std::string name = node->nodeName(); if (name == "replace" || name == "remove" || name == "incl" || name == "from_zk") continue; std::string value = node->nodeValue(); attrs_kv.push_back(std::make_pair(name, value)); } std::sort(attrs_kv.begin(), attrs_kv.end()); ElementIdentifier res; res.push_back(element->nodeName()); for (const auto & attr : attrs_kv) { res.push_back(attr.first); res.push_back(attr.second); } return res; }
/** * Takes a pointer to an XML node that is assumed to point at a "material" * tag. * It reads the definition and produces a new Material object. * @param element A pointer to an Element node that is a "material" tag * @return A new Material object */ Material MaterialXMLParser::parse(Poco::XML::Element *element) const { using namespace Poco::XML; typedef AutoPtr<NamedNodeMap> NamedNodeMapPtr; NamedNodeMapPtr attrs = element->attributes(); const auto id = attrs->getNamedItem(ID_ATT); if (!id || id->nodeValue().empty()) { throw std::invalid_argument("MaterialXMLReader::read() - No 'id' tag found " "or emptry string provided."); } attrs->removeNamedItem(ID_ATT); MaterialBuilder builder; builder.setName(id->nodeValue()); const auto nattrs = attrs->length(); for (unsigned long i = 0; i < nattrs; ++i) { Node *node = attrs->item(i); addToBuilder(&builder, node->nodeName(), node->nodeValue()); } return builder.build(); }
void ConfigProcessor::doIncludesRecursive( XMLDocumentPtr config, XMLDocumentPtr include_from, Node * node, zkutil::ZooKeeperNodeCache * zk_node_cache, std::unordered_set<std::string> & contributing_zk_paths) { if (node->nodeType() == Node::TEXT_NODE) { for (auto & substitution : substitutions) { std::string value = node->nodeValue(); bool replace_occured = false; size_t pos; while ((pos = value.find(substitution.first)) != std::string::npos) { value.replace(pos, substitution.first.length(), substitution.second); replace_occured = true; } if (replace_occured) node->setNodeValue(value); } } if (node->nodeType() != Node::ELEMENT_NODE) return; /// Substitute <layer> for the number extracted from the hostname only if there is an /// empty <layer> tag without attributes in the original file. if ( node->nodeName() == "layer" && !node->hasAttributes() && !node->hasChildNodes() && node->nodeValue().empty()) { NodePtr new_node = config->createTextNode(layerFromHost()); node->appendChild(new_node); return; } NamedNodeMapPtr attributes = node->attributes(); Node * incl_attribute = attributes->getNamedItem("incl"); Node * from_zk_attribute = attributes->getNamedItem("from_zk"); if (incl_attribute && from_zk_attribute) throw Poco::Exception("both incl and from_zk attributes set for element <" + node->nodeName() + ">"); /// Replace the original contents, not add to it. bool replace = attributes->getNamedItem("replace"); auto process_include = [&](const Node * include_attr, const std::function<Node * (const std::string &)> & get_node, const char * error_msg) { std::string name = include_attr->getNodeValue(); Node * node_to_include = get_node(name); if (!node_to_include) { if (attributes->getNamedItem("optional")) node->parentNode()->removeChild(node); else if (throw_on_bad_incl) throw Poco::Exception(error_msg + name); else LOG_WARNING(log, error_msg << name); } else { Element * element = dynamic_cast<Element *>(node); element->removeAttribute("incl"); element->removeAttribute("from_zk"); if (replace) { while (Node * child = node->firstChild()) node->removeChild(child); element->removeAttribute("replace"); } NodeListPtr children = node_to_include->childNodes(); for (size_t i = 0; i < children->length(); ++i) { NodePtr new_node = config->importNode(children->item(i), true); node->appendChild(new_node); } NamedNodeMapPtr from_attrs = node_to_include->attributes(); for (size_t i = 0; i < from_attrs->length(); ++i) { element->setAttributeNode(dynamic_cast<Attr *>(config->importNode(from_attrs->item(i), true))); } } }; auto get_incl_node = [&](const std::string & name) { return include_from ? include_from->getNodeByPath("yandex/" + name) : nullptr; }; if (incl_attribute) process_include(incl_attribute, get_incl_node, "Include not found: "); if (from_zk_attribute) { contributing_zk_paths.insert(from_zk_attribute->getNodeValue()); if (zk_node_cache) { XMLDocumentPtr zk_document; auto get_zk_node = [&](const std::string & name) -> Node * { std::optional<std::string> contents = zk_node_cache->get(name); if (!contents) return nullptr; /// Enclose contents into a fake <from_zk> tag to allow pure text substitutions. zk_document = dom_parser.parseString("<from_zk>" + *contents + "</from_zk>"); return getRootNode(zk_document.get()); }; process_include(from_zk_attribute, get_zk_node, "Could not get ZooKeeper node: "); } } NodeListPtr children = node->childNodes(); for (size_t i = 0; i < children->length(); ++i) { doIncludesRecursive(config, include_from, children->item(i), zk_node_cache, contributing_zk_paths); } }