2016-11-24 7 views
1

MoultingYaml является распылителем.json похожим на YAML и очень полезным как таковой.Преобразование YAML в/из JSON с использованием MoultingYaml

Однако он не предоставляет готовую поддержку для преобразования YAML < -> JSON. Я думаю, что это было бы полезно, по крайней мере, в качестве примерного кода с использованием, например, spray.json, что проект тесно связан.

Если у кого-то есть намеки/указатели на создание такого упрощенного кода, спасибо. Если нет, я, вероятно, придумаю это и опубликую здесь.

ответ

0

Вы можете конвертировать YAML/JSON в промежуточный формат объекта scala. Нечто подобное:

scala> import net.jcazevedo.moultingyaml.DefaultYamlProtocol._                            
import net.jcazevedo.moultingyaml.DefaultYamlProtocol._                              

scala> import net.jcazevedo.moultingyaml._                                 
import net.jcazevedo.moultingyaml._                                   

scala> import spray.json.DefaultJsonProtocol._                                
import spray.json.DefaultJsonProtocol._                                  

scala> import spray.json._                                     
import spray.json._                                      

scala> val jsonStr = "[1,2,3]"                                    
jsonStr: String = [1,2,3]                                     

scala> val jsonAst = jsonStr.parseJson                                  
jsonAst: spray.json.JsValue = [1,2,3]                                  

scala> val yamlAst = jsonAst.convertTo[List[Int]](spray.json.DefaultJsonProtocol.listFormat).toYaml(net.jcazevedo.moultingyaml.DefaultYamlProtocol.listFormat)    
yamlAst: net.jcazevedo.moultingyaml.YamlValue = YamlArray(Vector(YamlNumber(1), YamlNumber(2), YamlNumber(3)))                

scala> val yamlStr = yamlAst.prettyPrint                                 
yamlStr: String =                                       
"- 1                                          
- 2                                           
- 3                                           
"                                           

scala> val recoveredJsonAst = yamlAst.convertTo[List[Int]](net.jcazevedo.moultingyaml.DefaultYamlProtocol.listFormat).toJson(spray.json.DefaultJsonProtocol.listFormat)  
recoveredJsonAst: spray.json.JsValue = [1,2,3]                                

scala> val recoveredJsonStr = recoveredJsonAst.prettyPrint                             
recoveredJsonStr: String = [1, 2, 3]       

Здесь YAML AST преобразуется в объект домена List[Int], а затем JSON AST, и наоборот. Вы можете сделать прямое преобразование между АСТ, но тогда вам придется писать это самостоятельно - больше работы, но лучше.

Приятно, что библиотека YAML имитирует знакомый интерфейс библиотеки JSON, но дело с имплицитами усложняется. Кроме того, из-за этого сложнее решить такие методы, как convertTo. Импорт, как listFormat становятся неоднозначными и т.д.

Немного чище, когда есть меньше конфликтов:

scala> case class Test(v: Int)                           
defined class Test                              


scala> import net.jcazevedo.moultingyaml.DefaultYamlProtocol._                   
import net.jcazevedo.moultingyaml.DefaultYamlProtocol._                     

scala> import net.jcazevedo.moultingyaml._                        
import net.jcazevedo.moultingyaml._                          

scala> import spray.json.DefaultJsonProtocol._                       
import spray.json.DefaultJsonProtocol._                         

scala> import spray.json._                            
import spray.json._                              


scala> implicit val TestAsJson = jsonFormat1(Test)                      
TestAsJson: spray.json.RootJsonFormat[Test] = [email protected]          

scala> implicit val TestAsYaml = yamlFormat1(Test)                      
TestAsYaml: net.jcazevedo.moultingyaml.YamlFormat[Test] = [email protected]     

scala> val jsonStr = """{"v":1}"""                          
jsonStr: String = {"v":1}                            

scala> val jsonAst = jsonStr.parseJson                         
jsonAst: spray.json.JsValue = {"v":1}                         

scala> val yamlAst = jsonAst.convertTo[Test].toYaml                      
yamlAst: net.jcazevedo.moultingyaml.YamlValue = YamlObject(Map(YamlString(v) -> YamlNumber(1)))           

scala> val yamlStr = yamlAst.prettyPrint                         
yamlStr: String =                              
"v: 1                                 
"                                  

scala> val recoveredJsonAst = yamlAst.convertTo[Test].toJson                    
recoveredJsonAst: spray.json.JsValue = {"v":1}                       

scala> val recoveredJsonStr = recoveredJsonAst.prettyPrint                    
recoveredJsonStr: String =                            
{                                  
    "v": 1                                 
}   
+0

Спасибо @aleksey У меня есть непосредственное приготовление раствора AST-to-AST. Вывешивать его здесь, как только у меня будут тесты для этого, и они пройдут. Мне нужно поддерживать «любые» данные JSON. – akauppi

0

Это то, что я придумал.

import spray.json._ 
import net.jcazevedo.{moultingyaml => my} 
import net.jcazevedo.moultingyaml._ 
import net.jcazevedo.moultingyaml.DefaultYamlProtocol._ 

object JsonYamlProtocol extends my.CollectionFormats { 

    implicit object JsValueYamlFormat extends YamlFormat[JsValue] { 

    override 
    def write(jv: JsValue) = jv match { 
     case JsNumber(n) => YamlNumber(n) 
     case JsString(s) => YamlString(s) 
     case a: JsArray => seqFormat[JsValue].write(a.elements) 
     case o: JsObject => mapFormat[String,JsValue].write(o.fields) 
     case JsBoolean(b) => YamlBoolean(b) 
     case JsNull => YamlNull 
     case x => my.serializationError(s"Unexpected JSON value: $x") 
    } 

    override 
    def read(yv: YamlValue): JsValue = yv match { 
     // tbd. probably can be simplified 
     case x: YamlNumber[_] => x.value match { 
     //case xx: Int => JsNumber(xx) 
     //case xx: Double => JsNumber(xx) 
     case xx: BigDecimal => JsNumber(xx) 
     } 
     case YamlString(s) => JsString(s) 
     case a: YamlArray => JsArray(vectorFormat[JsValue].read(a)) 
     case o: YamlObject => JsObject(mapFormat[String, JsValue].read(o)) 
     case YamlBoolean(b) => JsBoolean(b) 
     case YamlNull => JsNull 
     case x => my.deserializationError(s"Unexpected YAML value: $x") 
    } 
    } 

    implicit object JsObjectYamlFormat extends YamlFormat[JsObject] { 

    override 
    def write(jso: JsObject): YamlValue = jso.fields.toYaml 

    override 
    def read(yv: YamlValue): JsObject = yv.convertTo[JsValue] match { 
     case jso: JsObject => jso 
     case x => my.deserializationError(s"Expected YAML object, got: $x") 
    } 
    } 
} 

У меня есть тесты на это. Скажите, пожалуйста, кто-то хочет посмотреть.

+0

Если все работает хорошо, возможно, вам следует опубликовать банку в репозиторий maven;). –

+0

Я хотел бы получить идеи о том, как лучше справляться с ситуацией «Ямль-номер». Это немного отличается от JSON в этом аспекте. – akauppi

+1

Отправленный PR-запрос о конверсии 'YamlNumber': https://github.com/jcazevedo/moultingyaml/pull/20 – akauppi

 Смежные вопросы

  • Нет связанных вопросов^_^