2010-10-16 16 views
9

Estoy tratando de escribir una implementación muy simple de la biblioteca Document Object Model para proporcionar una estructura de datos genérica para usar en mis proyectos futuros. Para simplificar, definí solo tres clases principales: node, element y attribute. Un nodo se define por su nombre (por ejemplo, todas las etiquetas html) y básicamente es un contenedor para un elemento que puede ser tanto de texto como de subnodos (almacenado en un std::vector<node>).¿Cómo implementar una estructura de datos DOM genérica en C++?

Simplemente no puedo entender cómo definir una estructura de árbol completa.

Necesito interfaces con plantilla para las clases a las que me he referido.

Ejemplo de uso:

element<string> txt1("Some text"); 

element< element<string> > div1("div", txt1); 

no quiero crear un nivel de abstracción completa DOM con soporte completo de XML. Solo necesito ideas para organizar la información en estilo DOM. No se requiere un análisis sintáctico

¡Gracias de antemano!

+0

+1, ahora que entiendo la pregunta mejor. Pensé que estabas tratando de implementar una biblioteca XML :) –

Respuesta

1

En lugar de tratar de escribir cada nodo fuertemente basado en el número de padres que ha, organizar el código como una estructura de árbol:

class Element 
{ 
public: 
    std::string Name; 
    std::map<std::string, std::string, std::less<std::string> > Attributes; 
    std::list<Element> Children; 
}; 

Su interfaz pública probablemente verá muy diferente de este. Solo intento mostrar el diseño de tipo general.

Realmente no necesita las funciones Nodo o Atributo, a menos que necesite iterar sobre ellas en una colección junto con Elementos. Es una característica útil para las bibliotecas XML DOM, pero si solo está tratando de crear una estructura de datos, no tiene que seguir el diseño DOM al pie de la letra.

De hecho, si sólo va para una estructura de datos genérica, es posible que quieran una bolsa de propiedades:

#include<map> 
#include<string> 
#include<iostream> 

class PropertyBag; 
typedef std::map<std::string, PropertyBag> PropertyMap; 

class PropertyBag : public PropertyMap 
{ 
public: 
    PropertyBag(const std::string& value) 
    : value(value) 
    { 
    } 

    PropertyBag& operator=(const std::string& value) 
    { 
    this->value = value; 
    return *this; 
    } 

    operator std::string&() { return value; } 

private: 
    std::string value; 

    friend PropertyMap::mapped_type& PropertyMap::operator[](const PropertyMap::key_type&); 
    PropertyBag() { } 
}; 

void SomeFunction(const std::string& value) 
{ 
    std::cout << value << "\n"; 
} 

int main(int argc, char* argv[]) 
{ 
    PropertyBag config("configuration root"); 
    config["child1"] = "value1"; 
    config["child1"]["subchild1"] = "value2"; 

    SomeFunction(config["child1"]); 
    SomeFunction(config["child1"]["subchild1"]); 
    return 0; 
} 

sólo hablar de la sintaxis, también se puede tratar de conseguir difícil con sobrecarga operator() y/o métodos de encadenamiento:

PropertyBag& SomeMethod(const std::string& someParam) 
{ 
    // do something here... 
    return *this; 
} 

PropertyBag& operator()(const std::string& p1, const std::string& p2) 
{ 
    // ... 
    return *this; 
} 

// ... 

Configuration config1("root") 
    .SomeMethod("p1") 
    .SomeMethod("p2"); 
Configuration config2("root") 
    ("Something", "blah") 
    ("sizzle", "V2"); 

Imagino que cuanto menos duplicación de texto/código, mejor. Cuanto más cerca pueda hacer que su código tenga una sintaxis como JSON o YAML, mejor.

Una vez que sale C++ 0x, puede tener opciones mucho más simples disponibles para usted.También puede consultar el boost::assign library para obtener una sintaxis de inicialización fácil de usar en su estructura de datos.

También puede buscar en el boost::any library un tipo de datos que puede usar como valor, en lugar de cadenas (admite un método seguro para insertar cualquier valor, siempre que lo extraiga del mismo tipo).

+0

@Merlyn: la lista tiene un rendimiento de tiempo de ejecución horrible, ¿estás seguro de que no quieres un vector aquí? –

+1

@ Matthieu: una lista representa mejor las operaciones que harías en una estructura como esta. No sabe el tamaño para empezar, y nunca haría acceso basado en índice en los niños. En este escenario, una lista puede tener un mejor rendimiento para la construcción, y tan rápido para el cruce. Pero en la vida real, este tipo de desempeño rara vez va a ser un cuello de botella, y si lo es, se le ocurriría una solución de almacenamiento personalizada para esa parte de la aplicación, en lugar de una estructura de datos genérica. –

+1

@Merlyn: buscar una solución de almacenamiento personalizada es una solución de último recurso, reservada a los expertos. En cuanto a la opción de la lista, estoy totalmente en desacuerdo. La primera opción de un contenedor debe ser 'vector' o' deque', porque son los más simples. Solo si tienes requisitos específicos deberías cambiar: 'unordered_set' para unicity,' set' para ordenar, 'stack' /' queue' para acceso específico, etc ... la única ventaja de usar 'list', en general, es la garantía de invalidación del iterador. –

0

Si miras mis respuestas anteriores, verás que soy un defensor de las plantillas, pero si no tienes otros requisitos, solo se interpondrán en el camino. A los analizadores no les gustan muchos tipos diferentes con los que lidiar. (Aunque dices que no necesitas un analizador - ¿eh?)

El objetivo de XML y DOM es facilitar la traducción hacia y desde cualquier estructura interna. No solo no necesita definir una plantilla de nodo XML, no debería necesitar ningún tipo de estructura de datos personalizada. Cualquier estructura ya está en estilo DOM. Los DAG son problemáticos, porque son un poco de árboles y un poco de gráficos, pero no insinúas que estás golpeando ese tipo de obstáculo.

Usted dice (en el comentario de la respuesta eliminada) que no desea utilizar una biblioteca existente. ¿Por qué? ¿Qué es lo que realmente estás tratando de hacer?

+0

"Aunque dices que no necesitas un analizador sintáctico, ¿eh?" ¡Sí! Así es, ¡no necesito un analizador! Mi parsing mathod es un procedimiento muy implícito. Puedo mostrarte algunos ejemplos cuando lo tengo hecho. Lo que estoy haciendo es un motor de plantillas para html, por lo que quiero tener una representación de datos html abstracta para utilizar en la manipulación del árbol DOM. – Rizo

+0

@Rizo: en ese caso, está escribiendo un analizador sintáctico y está creando su propia biblioteca HTML (no XML). Y como dije, a menos que haya una razón para usar plantillas, simplemente se interpondrán en el camino. – Potatoswatter

+0

Solo pensé que xml era sintáctica y lógicamente equivalente a html (¿no?). – Rizo

Cuestiones relacionadas