|
@@ -66,6 +66,8 @@ struct find_node_by_name_predicate {
|
|
|
}
|
|
|
};
|
|
|
|
|
|
+/// @brief Will convert an attribute to its int value.
|
|
|
+/// @tparam TNodeType The node type.
|
|
|
template <class TNodeType>
|
|
|
struct NodeConverter {
|
|
|
public:
|
|
@@ -78,19 +80,37 @@ public:
|
|
|
using XmlNode = pugi::xml_node;
|
|
|
using XmlAttribute = pugi::xml_attribute;
|
|
|
|
|
|
+/// @brief The Xml-Parser class.
|
|
|
+///
|
|
|
+/// Use this parser if you have to import any kind of xml-format.
|
|
|
+///
|
|
|
+/// An example:
|
|
|
+/// @code
|
|
|
+/// TXmlParser<XmlNode> theParser;
|
|
|
+/// if (theParser.parse(fileStream)) {
|
|
|
+/// auto node = theParser.getRootNode();
|
|
|
+/// for ( auto currentNode : node.children()) {
|
|
|
+/// // Will loop over all children
|
|
|
+/// }
|
|
|
+/// }
|
|
|
+/// @endcode
|
|
|
+/// @tparam TNodeType
|
|
|
template <class TNodeType>
|
|
|
class TXmlParser {
|
|
|
public:
|
|
|
+ /// @brief The default class constructor.
|
|
|
TXmlParser() :
|
|
|
mDoc(nullptr),
|
|
|
mData() {
|
|
|
// empty
|
|
|
}
|
|
|
|
|
|
+ /// @brief The class destructor.
|
|
|
~TXmlParser() {
|
|
|
clear();
|
|
|
}
|
|
|
|
|
|
+ /// @brief Will clear the parsed xml-file.
|
|
|
void clear() {
|
|
|
if(mData.empty()) {
|
|
|
mDoc = nullptr;
|
|
@@ -101,6 +121,9 @@ public:
|
|
|
mDoc = nullptr;
|
|
|
}
|
|
|
|
|
|
+ /// @brief Will search for a child-node by its name
|
|
|
+ /// @param name [in] The name of the child-node.
|
|
|
+ /// @return The node instance or nullptr, if nothing was found.
|
|
|
TNodeType *findNode(const std::string &name) {
|
|
|
if (name.empty()) {
|
|
|
return nullptr;
|
|
@@ -119,10 +142,16 @@ public:
|
|
|
return &mCurrent;
|
|
|
}
|
|
|
|
|
|
+ /// @brief Will return true, if the node is a child-node.
|
|
|
+ /// @param name [in] The name of the child node to look for.
|
|
|
+ /// @return true, if the node is a child-node or false if not.
|
|
|
bool hasNode(const std::string &name) {
|
|
|
return nullptr != findNode(name);
|
|
|
}
|
|
|
|
|
|
+ /// @brief Will parse an xml-file from a given stream.
|
|
|
+ /// @param stream The input stream.
|
|
|
+ /// @return true, if the parsing was successful, false if not.
|
|
|
bool parse(IOStream *stream) {
|
|
|
if (nullptr == stream) {
|
|
|
ASSIMP_LOG_DEBUG("Stream is nullptr.");
|
|
@@ -138,36 +167,67 @@ public:
|
|
|
pugi::xml_parse_result parse_result = mDoc->load_string(&mData[0], pugi::parse_full);
|
|
|
if (parse_result.status == pugi::status_ok) {
|
|
|
return true;
|
|
|
- } else {
|
|
|
- std::ostringstream oss;
|
|
|
- oss << "Error while parsing XML: " << parse_result.description() << " @ " << parse_result.offset;
|
|
|
- ASSIMP_LOG_DEBUG(oss.str());
|
|
|
- return false;
|
|
|
- }
|
|
|
+ }
|
|
|
+
|
|
|
+ ASSIMP_LOG_DEBUG("Error while parse xml.", std::string(parse_result.description()), " @ ", parse_result.offset);
|
|
|
+
|
|
|
+ return false;
|
|
|
}
|
|
|
|
|
|
+ /// @brief Will return truem if a root node is there.
|
|
|
+ /// @return true in case of an existing root.
|
|
|
+ bool hasRoot() const {
|
|
|
+ return nullptr != mDoc;
|
|
|
+ }
|
|
|
+ /// @brief Will return the document pointer, is nullptr if no xml-file was parsed.
|
|
|
+ /// @return The pointer showing to the document.
|
|
|
pugi::xml_document *getDocument() const {
|
|
|
return mDoc;
|
|
|
}
|
|
|
|
|
|
+ /// @brief Will return the root node, const version.
|
|
|
+ /// @return The root node.
|
|
|
const TNodeType getRootNode() const {
|
|
|
+ static pugi::xml_node none;
|
|
|
+ if (nullptr == mDoc) {
|
|
|
+ return none;
|
|
|
+ }
|
|
|
return mDoc->root();
|
|
|
}
|
|
|
|
|
|
+ /// @brief Will return the root node, non-const version.
|
|
|
+ /// @return The root node.
|
|
|
TNodeType getRootNode() {
|
|
|
+ static pugi::xml_node none;
|
|
|
+ if (nullptr == mDoc) {
|
|
|
+ return none;
|
|
|
+ }
|
|
|
return mDoc->root();
|
|
|
}
|
|
|
|
|
|
+ /// @brief Will check if a node with the given name is in.
|
|
|
+ /// @param node [in] The node to look in.
|
|
|
+ /// @param name [in] The name of the child-node.
|
|
|
+ /// @return true, if node was found, false if not.
|
|
|
static inline bool hasNode(XmlNode &node, const char *name) {
|
|
|
pugi::xml_node child = node.find_child(find_node_by_name_predicate(name));
|
|
|
return !child.empty();
|
|
|
}
|
|
|
|
|
|
+ /// @brief Will check if an attribute is part of the XmlNode.
|
|
|
+ /// @param xmlNode [in] The node to search in.
|
|
|
+ /// @param name [in} The attribute name to look for.
|
|
|
+ /// @return true, if the was found, false if not.
|
|
|
static inline bool hasAttribute(XmlNode &xmlNode, const char *name) {
|
|
|
pugi::xml_attribute attr = xmlNode.attribute(name);
|
|
|
return !attr.empty();
|
|
|
}
|
|
|
|
|
|
+ /// @brief Will try to get an unsigned int attribute value.
|
|
|
+ /// @param xmlNode [in] The node to search in.
|
|
|
+ /// @param name [in] The attribute name to look for.
|
|
|
+ /// @param val [out] The unsigned int value from the attribute.
|
|
|
+ /// @return true, if the node contains an attribute with the given name and if the value is an unsigned int.
|
|
|
static inline bool getUIntAttribute(XmlNode &xmlNode, const char *name, unsigned int &val) {
|
|
|
pugi::xml_attribute attr = xmlNode.attribute(name);
|
|
|
if (attr.empty()) {
|
|
@@ -178,6 +238,11 @@ public:
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
+ /// @brief Will try to get an int attribute value.
|
|
|
+ /// @param xmlNode [in] The node to search in.
|
|
|
+ /// @param name [in] The attribute name to look for.
|
|
|
+ /// @param val [out] The int value from the attribute.
|
|
|
+ /// @return true, if the node contains an attribute with the given name and if the value is an int.
|
|
|
static inline bool getIntAttribute(XmlNode &xmlNode, const char *name, int &val ) {
|
|
|
pugi::xml_attribute attr = xmlNode.attribute(name);
|
|
|
if (attr.empty()) {
|
|
@@ -188,6 +253,11 @@ public:
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
+ /// @brief Will try to get a real attribute value.
|
|
|
+ /// @param xmlNode [in] The node to search in.
|
|
|
+ /// @param name [in] The attribute name to look for.
|
|
|
+ /// @param val [out] The real value from the attribute.
|
|
|
+ /// @return true, if the node contains an attribute with the given name and if the value is a real.
|
|
|
static inline bool getRealAttribute( XmlNode &xmlNode, const char *name, ai_real &val ) {
|
|
|
pugi::xml_attribute attr = xmlNode.attribute(name);
|
|
|
if (attr.empty()) {
|
|
@@ -201,7 +271,12 @@ public:
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
- static inline bool getFloatAttribute(XmlNode &xmlNode, const char *name, float &val ) {
|
|
|
+ /// @brief Will try to get a float attribute value.
|
|
|
+ /// @param xmlNode [in] The node to search in.
|
|
|
+ /// @param name [in] The attribute name to look for.
|
|
|
+ /// @param val [out] The float value from the attribute.
|
|
|
+ /// @return true, if the node contains an attribute with the given name and if the value is a float.
|
|
|
+ static inline bool getFloatAttribute(XmlNode &xmlNode, const char *name, float &val) {
|
|
|
pugi::xml_attribute attr = xmlNode.attribute(name);
|
|
|
if (attr.empty()) {
|
|
|
return false;
|
|
@@ -212,7 +287,12 @@ public:
|
|
|
|
|
|
}
|
|
|
|
|
|
- static inline bool getDoubleAttribute( XmlNode &xmlNode, const char *name, double &val ) {
|
|
|
+ /// @brief Will try to get a double attribute value.
|
|
|
+ /// @param xmlNode [in] The node to search in.
|
|
|
+ /// @param name [in] The attribute name to look for.
|
|
|
+ /// @param val [out] The double value from the attribute.
|
|
|
+ /// @return true, if the node contains an attribute with the given name and if the value is a double.
|
|
|
+ static inline bool getDoubleAttribute(XmlNode &xmlNode, const char *name, double &val) {
|
|
|
pugi::xml_attribute attr = xmlNode.attribute(name);
|
|
|
if (attr.empty()) {
|
|
|
return false;
|
|
@@ -222,6 +302,11 @@ public:
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
+ /// @brief Will try to get a std::string attribute value.
|
|
|
+ /// @param xmlNode [in] The node to search in.
|
|
|
+ /// @param name [in] The attribute name to look for.
|
|
|
+ /// @param val [out] The std::string value from the attribute.
|
|
|
+ /// @return true, if the node contains an attribute with the given name and if the value is a std::string.
|
|
|
static inline bool getStdStrAttribute(XmlNode &xmlNode, const char *name, std::string &val) {
|
|
|
pugi::xml_attribute attr = xmlNode.attribute(name);
|
|
|
if (attr.empty()) {
|
|
@@ -232,6 +317,11 @@ public:
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
+ /// @brief Will try to get a bool attribute value.
|
|
|
+ /// @param xmlNode [in] The node to search in.
|
|
|
+ /// @param name [in] The attribute name to look for.
|
|
|
+ /// @param val [out] The bool value from the attribute.
|
|
|
+ /// @return true, if the node contains an attribute with the given name and if the value is a bool.
|
|
|
static inline bool getBoolAttribute( XmlNode &xmlNode, const char *name, bool &val ) {
|
|
|
pugi::xml_attribute attr = xmlNode.attribute(name);
|
|
|
if (attr.empty()) {
|
|
@@ -243,6 +333,10 @@ public:
|
|
|
|
|
|
}
|
|
|
|
|
|
+ /// @brief Will try to get the value of the node as a string.
|
|
|
+ /// @param node [in] The node to search in.
|
|
|
+ /// @param text [out] The value as a text.
|
|
|
+ /// @return true, if the value can be read out.
|
|
|
static inline bool getValueAsString( XmlNode &node, std::string &text ) {
|
|
|
text = std::string();
|
|
|
if (node.empty()) {
|
|
@@ -254,6 +348,10 @@ public:
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
+ /// @brief Will try to get the value of the node as a float.
|
|
|
+ /// @param node [in] The node to search in.
|
|
|
+ /// @param text [out] The value as a float.
|
|
|
+ /// @return true, if the value can be read out.
|
|
|
static inline bool getValueAsFloat( XmlNode &node, ai_real &v ) {
|
|
|
if (node.empty()) {
|
|
|
return false;
|
|
@@ -273,17 +371,36 @@ public:
|
|
|
|
|
|
using XmlParser = TXmlParser<pugi::xml_node>;
|
|
|
|
|
|
+/// @brief This class declares an iterator to loop through all children of the root node.
|
|
|
class XmlNodeIterator {
|
|
|
public:
|
|
|
- XmlNodeIterator(XmlNode &parent) :
|
|
|
+ /// @brief The iteration mode.
|
|
|
+ enum IterationMode {
|
|
|
+ PreOrderMode, ///< Pre-ordering, get the values, continue the iteration.
|
|
|
+ PostOrderMode ///< Post-ordering, continue the iteration, get the values.
|
|
|
+ };
|
|
|
+ /// @brief The class constructor
|
|
|
+ /// @param parent [in] The xml parent to to iterate through.
|
|
|
+ /// @param mode [in] The iteration mode.
|
|
|
+ explicit XmlNodeIterator(XmlNode &parent, IterationMode mode) :
|
|
|
mParent(parent),
|
|
|
mNodes(),
|
|
|
mIndex(0) {
|
|
|
+ if (mode == PreOrderMode) {
|
|
|
+ collectChildrenPreOrder(parent);
|
|
|
+ } else {
|
|
|
+ collectChildrenPostOrder(parent);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /// @brief The class destructor.
|
|
|
+ ~XmlNodeIterator() {
|
|
|
// empty
|
|
|
}
|
|
|
|
|
|
+ /// @brief Will iterate through all children in pre-order iteration.
|
|
|
+ /// @param node [in] The nod to iterate through.
|
|
|
void collectChildrenPreOrder( XmlNode &node ) {
|
|
|
-
|
|
|
if (node != mParent && node.type() == pugi::node_element) {
|
|
|
mNodes.push_back(node);
|
|
|
}
|
|
@@ -292,6 +409,8 @@ public:
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ /// @brief Will iterate through all children in post-order iteration.
|
|
|
+ /// @param node [in] The nod to iterate through.
|
|
|
void collectChildrenPostOrder(XmlNode &node) {
|
|
|
for (XmlNode currentNode = node.first_child(); currentNode; currentNode = currentNode.next_sibling()) {
|
|
|
collectChildrenPostOrder(currentNode);
|
|
@@ -301,6 +420,9 @@ public:
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ /// @brief Will iterate through all collected nodes.
|
|
|
+ /// @param next The next node, if there is any.
|
|
|
+ /// @return true, if there is a node left.
|
|
|
bool getNext(XmlNode &next) {
|
|
|
if (mIndex == mNodes.size()) {
|
|
|
return false;
|
|
@@ -312,14 +434,19 @@ public:
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
+ /// @brief Will return the number of collected nodes.
|
|
|
+ /// @return The number of collected nodes.
|
|
|
size_t size() const {
|
|
|
return mNodes.size();
|
|
|
}
|
|
|
|
|
|
+ /// @brief Returns true, if the node is empty.
|
|
|
+ /// @return true, if the node is empty, false if not.
|
|
|
bool isEmpty() const {
|
|
|
return mNodes.empty();
|
|
|
}
|
|
|
|
|
|
+ /// @brief Will clear all collected nodes.
|
|
|
void clear() {
|
|
|
if (mNodes.empty()) {
|
|
|
return;
|