2011-11-06 15 views
6

Lo que tengo Tengo plantillas que están almacenadas en una base de datos y datos JSON que se convierten en un diccionario en C#.¿Qué enfoque para crear plantillas en C# debo tomar?

Ejemplo:

Plantilla: "Hola {FirstName}"

datos: "{nombre: 'Jack'}"

Esto funciona fácilmente con un nivel de datos mediante el uso de una expresión regular para sacar cualquier cosa dentro de {} en la plantilla.

Lo que quiero Me gustaría poder profundizar en el JSON que en la primera capa.

Ejemplo:

Plantilla: "Hola {Nombre: {primer}}"

datos: "{Nombre: {Primera: 'Jack', Última: 'Smith'}}"

¿Qué enfoque debo tomar? (Y alguna orientación sobre dónde empezar con su selección)

  1. Una expresión regular
  2. No utilizar JSON en la plantilla (a favor de XSLT o algo similar)
  3. Algo más

También me gustaría poder ver los datos en la plantilla, ¡pero no tengo ni idea de dónde comenzar con esa!

Gracias montones

Respuesta

2

Aquí es cómo lo haría:

cambiar la plantilla de este formato Hi {Name.First}

Ahora cree un JavaScriptSerializer para convertir JSON en Dictionary<string, object>

JavaScriptSerializer jss = new JavaScriptSerializer(); 
dynamic d = jss.Deserialize(data, typeof(object)); 

Ahora la variable d tiene los valores de su JSON en un diccionario.

Teniendo eso usted puede ejecutar su plantilla contra una expresión regular para reemplazar {X.Y.Z.N} con las teclas del diccionario, recursivamente.

Ejemplo completo:

public void Test() 
{ 
    // Your template is simpler 
    string template = "Hi {Name.First}"; 

    // some JSON 
    string data = @"{""Name"":{""First"":""Jack"",""Last"":""Smith""}}"; 

    JavaScriptSerializer jss = new JavaScriptSerializer(); 

    // now `d` contains all the values you need, in a dictionary 
    dynamic d = jss.Deserialize(data, typeof(object)); 

    // running your template against a regex to 
    // extract the tokens that need to be replaced 
    var result = Regex.Replace(template, @"{?{([^}]+)}?}", (m) => 
     { 
      // Skip escape values (ex: {{escaped value}}) 
      if (m.Value.StartsWith("{{")) 
       return m.Value; 

      // split the token by `.` to run against the dictionary 
      var pieces = m.Groups[1].Value.Split('.'); 
      dynamic value = d; 

      // go after all the pieces, recursively going inside 
      // ex: "Name.First" 

      // Step 1 (value = value["Name"]) 
      // value = new Dictionary<string, object> 
      // { 
      //  { "First": "Jack" }, { "Last": "Smith" } 
      // }; 

      // Step 2 (value = value["First"]) 
      // value = "Jack" 

      foreach (var piece in pieces) 
      { 
       value = value[piece]; // go inside each time 
      } 

      return value; 
     }); 
} 

yo no manejar excepciones (por ejemplo, el valor no se pudo encontrar), que puede manejar este caso y devolver el valor coincidente si no se ha encontrado. m.Value para el valor bruto o m.Groups[1].Value para la cadena entre {}.

2

ha pensado en el uso de Javascript como su lenguaje de script? Tuve un gran éxito con Jint, aunque el costo de inicio es alto. Otra opción es Jurassic, que no he usado yo mismo.

Si tiene una aplicación web, usando Razor tal vez una idea, see here.

El uso de Regex o cualquier tipo de análisis sintáctico de cadenas puede funcionar para cosas triviales, pero puede ser doloroso cuando se quiere una lógica o incluso jerarquías básicas. Si deserializar su JSON en Diccionarios anidadas, se puede construir un analizador con relativa facilidad:

// Untested and error prone, just to illustrate the concept 
var parts = "parentObj.childObj.property".split('.'); 
Dictionary<object,object> current = yourDeserializedObject; 
foreach(var key in parts.Take(parts.Length-1)){ 
    current = current[key]; 
} 
var value = current[parts.Last()]; 

Justo lo que haga, no hacen XSLT. Realmente, si XSLT es la respuesta, entonces la pregunta debe haber sido realmente desesperada :)

+0

Parece el escenario perfecto para XSLT. –

+0

Solo si te gusta la verbosidad que trae consigo. –

+0

Mi jefe estaría de acuerdo contigo Kirk, pero como dice Michael, es un poco grande para lo que estoy tratando de hacer. Y gracias a Michael, tu respuesta también es genial, pero solo puede dar un tic :) –

4

¡Estás de enhorabuena! SmartFormat hace exactamente lo que usted describe. Es una utilidad ligera de formato de cadena de fuente abierta.

Es compatible con marcadores de posición con nombre:

var template = " {Name:{Last}, {First}} "; 

var data = new { Name = new { First="Dwight", Last="Schrute" } }; 

var result = Smart.Format(template, data); 
// Outputs: " Schrute, Dwight " SURPRISE! 

También es compatible con lista de formatear:

var template = " {People:{}|, |, and} "; 

var data = new { People = new[]{ "Dwight", "Michael", "Jim", "Pam" } }; 

var result = Smart.Format(template, data); 
// Outputs: " Dwight, Michael, Jim, and Pam " 

Se puede extraer de las pruebas unitarias para Named Placeholders y List Formatter ver muchos más ejemplos!

Incluso tiene varias formas de manejo de errores (ignorar errores, errores de salida, errores de tiro).

Nota: la función de llamado marcador de posición utiliza la reflexión y/o búsquedas de diccionario, por lo que puede deserializar el JSON en objetos de C# o anidado Dictionaries, y será un gran trabajo!

Cuestiones relacionadas