JUST——简单转换下的JSON

1024 篇文章 46 订阅
611 篇文章 16 订阅

目录

介绍

背景

安装Nuget包

使用代码

使用JUST转换JSON

valueof

ifcondition

字符串和数学函数

Opearators

聚合函数

多维数组的聚合函数

批量函数

数组循环

嵌套数组循环(在上下文中循环)

数组分组

调用自定义函数

函数嵌套

多个参数和常量函数

检查是否存在

条件转换

动态属性

使用前缀针对多个模式的模式验证

基于数组令牌将JSON拆分为多个JSON(s)

 将JSON转换为其他数据格式

JSON到XML的示例

JSON到CSV的示例

链接到测试源代码(源代码现在也可用)


介绍

本文介绍如何使用JUST.NET库来转换JSON文档。

背景

JUST代表简单转换下的JSONXSLT是一种使用简单转换语言转换XML文档的非常流行的方法。

现在越来越多的应用程序使用JSON作为数据格式,因为它比XML更简单,体积更小。

但是,没有一种非常简单的方法来转换JSON文档。

我在.NET中创建了一个库,它允许使用非常简单的转换语言转换JSON文档。这是为JSON创建一个XSLT并行程序的尝试。

本文介绍如何使用该库。

安装Nuget

https://www.nuget.org上下载最新的JUST.NET 

Install-Package JUST

还提供dotnetcore版本:

Install-Package JUST.NETCore

还提供.NET标准版本。这是从现在开始支持的版本。

Install-Package JUST.NET

使用代码

下载Nuget包后,您将创建一个简单的控制台应用程序。
下面是一个简单的C#代码片段,您可以使用它来转换您的JSON

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

using JUST;
using System.IO;

namespace JUST.Test
{
    public class Program
    {
        public static void Main(string[] args)
        {
            string input = File.ReadAllText("Input.json");

            string transformer = File.ReadAllText("Transformer.json"); ;

            string transformedString = JsonTransformer.Transform(transformer, input);

            Console.WriteLine(transformedString);           
        }
    }
}

这里,Input.json是输入JSON文档,而Transformer.json是转换输入JSONJSON文档。

使用JUST转换JSON

JUST是一种转换语言,就像XSLT一样。它包含在转换器JSON内部使用的函数,用于将输入JSON转换为所需的输出JSON。本节介绍JUST中存在的各种函数以及它们如何用于转换JSON

每个JUST函数都以#字符开头。

valueof

此函数用于提取给定属性的值。使用属性的JSON路径提取该值。有关如何使用JSON路径的更多信息,请参阅:

考虑输入:

{
  "menu": {  
    "popup": {
      "menuitem": [
       {
          "value": "Open",
          "onclick": "OpenDoc()"
        },
        {
          "value": "Close",
          "onclick": "CloseDoc()"
        }
      ]
    }
  }
}

转换器:

{
  "result": {
    "Open": "#valueof($.menu.popup.menuitem[?(@.value=='Open')].onclick)",
    "Close": "#valueof($.menu.popup.menuitem[?(@.value=='Close')].onclick)"
  }
}

输出:

{
   "result":{"Open":"OpenDoc()","Close":"CloseDoc()"}
}

ifcondition

此条件被用于评估ifelse的条件。

ifcondition(condition expresson, evaluation expression, true result, false result)

所有四个参数都可以是'valueof'表达式或常量。

考虑输入:

{
  "menu": {
    "id" : "github",
    "repository" : "JUST"
  }
}

转换器:

{
  "ifconditiontesttrue": "#ifcondition
  (#valueof($.menu.id),github,#valueof($.menu.repository),fail)",
  "ifconditiontestfalse": "#ifcondition
  (#valueof($.menu.id),xml,#valueof($.menu.repository),fail)"
}

输出:

{
   "ifconditiontesttrue":"JUST",
   "ifconditiontestfalse":"fail"
}

字符串和数学函数

目前,只有基本的和经常使用stringmath功能在库中提供。

  • lastindexof(input string,search string)
  • firstindexof(input string,search string)
  • substring(input string,start index,length)
  • concat(string 1,string 2)
  • add(value 1,value 2)
  • subtract(value 1,value 2)
  • multiply(value 1,value 2)
  • divide(value 1,values 2)

考虑输入:

{
  "stringref": "thisisandveryunuasualandlongstring",
  "numbers": [ "1", "2", "3", "4", "5" ]
}

转换器:

{
  "stringresult": {
    "lastindexofand": "#lastindexof(#valueof($.stringref),and)",
    "firstindexofand": "#firstindexof(#valueof($.stringref),and)",
    "substring": "#substring(#valueof($.stringref),9,11)",
    "concat": "#concat(#valueof($.menu.id.file),#valueof($.menu.value.Window))"
  },
  "mathresult": {
    "add": "#add(#valueof($.numbers[0]),3)",
    "subtract": "#subtract(#valueof($.numbers[4]),#valueof($.numbers[0]))",
    "multiply": "#multiply(2,#valueof($.numbers[2]))",
    "divide": "#divide(9,3)"
  }
}

输出:

{"stringresult":
   {
    "lastindexofand":"21",
    "firstindexofand":"6",
    "substring":"veryunuasua",
    "concat":""
   },
   "mathresult":
   {
    "add":"4",
    "subtract":"4",
    "multiply":"6",
    "devide":"3"
   }
}

Opearators

添加了以下运算符来比较字符串和数字:

  • stringequals(string1, string2)
  • stringcontains(string1, string2)
  • mathequals(decimal1, decimal2)
  • mathgreaterthan(decimal1, decimal2)
  • mathlessthan(decimal1, decimal2)
  • mathgreaterthanorequalto(decimal1, decimal2)
  • mathlessthanorequalto(decimal1, decimal2)

考虑输入:

{
  "d": [ "one", "two", "three" ],
  "numbers": [ "1", "2", "3", "4", "5" ]
}

转换器:

{
  "mathresult": {
    "third_element_equals_3": "#ifcondition(#mathequals(#valueof($.numbers[2]),3),true,yes,no)",
    "third_element_greaterthan_2": 
          "#ifcondition(#mathgreaterthan(#valueof($.numbers[2]),2),true,yes,no)",
    "third_element_lessthan_4": 
          "#ifcondition(#mathlessthan(#valueof($.numbers[2]),4),true,yes,no)",
    "third_element_greaterthanorequals_4": 
          "#ifcondition(#mathgreaterthanorequalto(#valueof($.numbers[2]),4),true,yes,no)",
    "third_element_lessthanoreuals_2": 
          "#ifcondition(#mathlessthanorequalto(#valueof($.numbers[2]),2),true,yes,no)",
    "one_stringequals": "#ifcondition(#stringequals(#valueof($.d[0]),one),true,yes,no)",
    "one_stringcontains": "#ifcondition(#stringcontains(#valueof($.d[0]),n),true,yes,no)"
  }
}

输出:

{"mathresult":   {"third_element_equals_3":"yes","third_element_greaterthan_2":"yes",
   "third_element_lessthan_4":"yes","third_element_greaterthanorequals_4":"no",
   "third_element_lessthanoreuals_2":"no","one_stringequals":"yes","one_stringcontains":"yes"}}

聚合函数

为一维数组提供以下聚合函数:

  • concatall(array)
  • sum(array)
  • average(array)
  • min(array)
  • max(array)

Consider the input:-

Consider the input:-
{
  "d": [ "one", "two", "three" ],
  "numbers": [ "1", "2", "3", "4", "5" ]
}

转换器:

{
  "conacted": "#concatall(#valueof($.d))",
  "sum": "#sum(#valueof($.numbers))",
  "avg": "#average(#valueof($.numbers))",
  "min": "#min(#valueof($.numbers))",
  "max": "#max(#valueof($.numbers))"
}

输出:

{
    "conacted":"onetwothree",
    "sum":"15",
    "avg":"3",
    "min":"1",
    "max":"5"
}

多维数组的聚合函数

这些函数与上面的函数基本相同,唯一的区别是您还可以提供指向数组中特定元素的路径:

  • concatallatpath(array,path)
  • sumatpath(array,path)
  • averageatpath(array,path)
  • minatpath(array,path)
  • maxatpath(array,path)

考虑输入:

{
   "x": [
    {
      "v": {
        "a": "a1,a2,a3",
        "b": "1",
        "c": "10"
      }
    },
    {
      "v": {
        "a": "b1,b2",
        "b": "2",
        "c": "20"
      }
    },
    {
      "v": {
        "a": "c1,c2,c3",
        "b": "3",
        "c": "30"
      }
    }
  ]
}

转换器:

{
  "arrayconacted": "#concatallatpath(#valueof($.x),$.v.a)",
  "arraysum": "#sumatpath(#valueof($.x),$.v.c)",
  "arrayavg": "#averageatpath(#valueof($.x),$.v.c)",
  "arraymin": "#minatpath(#valueof($.x),$.v.b)",
  "arraymax": "#maxatpath(#valueof($.x),$.v.b)"
}

输出:

{
    "arrayconacted":"a1,a2,a3b1,b2c1,c2,c3",
    "arraysum":"60",
    "arrayavg":"20",
    "arraymin":"1",
    "arraymax":"3"
}

批量函数

以上所有函数都将属性值设置为输出JSON中的预定义属性。但是,在某些情况下,我们不知道输出会是什么样的,因为它取决于输入。为此提供了批量功能。它们与XSLT中的模板匹配函数相对应。

规则规定的批量函数必须是JSON对象的第一个属性。所有批量函数都表示为属性'#'的数组元素。

这些是截至目前提供的批量函数:

  • copy(path)
  • replace(path)
  • delete(path)

考虑输入:

{
  "tree": {
    "branch": {
      "leaf": "green",
      "flower": "red",
      "bird": "crow",
      "extra": { "twig":"birdnest" }
    },
    "ladder": {"wood": "treehouse" }
  }
}

转换器:

{
  "#": [ "#copy($)",  "#delete($.tree.branch.bird)", 
         "#replace($.tree.branch.extra,#valueof($.tree.ladder))" ],
  "othervalue" : "othervalue"
}

输出:

{
   "othervalue":"othervalue",
   "tree":{
    "branch":{
     "leaf":"green",
     "flower":"red",
     "extra":{
      "wood":"treehouse"
     }
    },
    "ladder":{
     "wood":"treehouse"
    }
  }
}

数组循环

在某些情况下,我们不希望将整个数组复制到目标JSON。我们可能希望将数组转换为不同的格式,或者在设置目标JSON时为每个元素设置一些特殊逻辑。
对于这些情况,我们将使用数组循环。

这些是为此目的提供的函数:

  • loop(path)——path是要循环的数组的路径
  • currentvalue()
  • currentvalueatpath(path) ——此处path表示数组内部的路径
  • lastvalueatpath(path)——此处path表示数组内部的路径
  • currentindex()
  • lastindex()
  • lastvalue()

考虑输入:

{
  "tree": {
    "branch": {
      "leaf": "green",
      "flower": "red",
      "bird": "crow",
      "extra": { "twig": "birdnest" }
    },
    "ladder": { "wood": "treehouse" }
  },
  "numbers": [ "1", "2", "3", "4" ],
  "arrayobjects": [
    {"country": {"name": "norway","language": "norsk"}},
    {
      "country": {
        "name": "UK",
        "language": "english"
      }
    },
    {
      "country": {
        "name": "Sweden",
        "language": "swedish"
      }
    }]
}

转换器:

{
  "iteration": {
    "#loop($.numbers)": {
      "CurrentValue": "#currentvalue()",
      "CurrentIndex": "#currentindex()",
      "IsLast": "#ifcondition(#currentindex(),#lastindex(),yes,no)",
      "LastValue": "#lastvalue()"
    }
  },
  "iteration2": {
    "#loop($.arrayobjects)": {
      "CurrentValue": "#currentvalueatpath($.country.name)",
      "CurrentIndex": "#currentindex()",
      "IsLast": "#ifcondition(#currentindex(),#lastindex(),yes,no)",
      "LastValue": "#lastvalueatpath($.country.language)"
    }
  },
  "othervalue": "othervalue"
}

输出:

{

"iteration":[
   {"CurrentValue":"1","CurrentIndex":"0",
   "IsLast":"no","LastValue":"4"},
   {"CurrentValue":"2","CurrentIndex":"1",
   "IsLast":"no","LastValue":"4"},
   {"CurrentValue":"3","CurrentIndex":"2",
   "IsLast":"no","LastValue":"4"},
   {"CurrentValue":"4","CurrentIndex":"3",
   "IsLast":"yes","LastValue":"4"}
  ],
   "iteration2":[
   {"CurrentValue":"norway","CurrentIndex":"0",
   "IsLast":"no","LastValue":"swedish"},
   {"CurrentValue":"UK","CurrentIndex":"1",
   "IsLast":"no","LastValue":"swedish"},
   {"CurrentValue":"Sweden","CurrentIndex":"2",
   "IsLast":"yes","LastValue":"swedish"}
  ],
"othervalue":"othervalue"
}

嵌套数组循环(在上下文中循环)

引入了一个新函数loopwithincontext ,其可以循环使用外部循环的上下文。

考虑输入:

{
  "NestedLoop": {
    "Organization": {
      "Employee": [
        {
          "Name": "E2",
          "Details": [
            {
              "Country": "Iceland",
              "Age": "30",
              "Name": "Sven",
              "Language": "Icelandic"
            }
          ]
        },
        {
          "Name": "E1",
          "Details": [
            {
              "Country": "Denmark",
              "Age": "30",
              "Name": "Svein",
              "Language": "Danish"
            }
          ]
        }
      ]
    }
  }
}

转换器:

{
  "hello": {
    "#loop($.NestedLoop.Organization.Employee)": {
      "CurrentName": "#currentvalueatpath($.Name)",
      "Details": {
        "#loopwithincontext($.Details)": {
          "CurrentCountry": "#currentvalueatpath($.Country)"
        }
      }
    }
  }
}

输出:

{ 
   "hello":[ 
      { 
         "CurrentName":"E2",
         "Details":[ 
            { 
               "CurrentCountry":"Iceland"
            }
         ]
      },
      { 
         "CurrentName":"E1",
         "Details":[ 
            { 
               "CurrentCountry":"Denmark"
            }
         ]
      }
   ]
}

数组分组

引入了类似于SQL GROUP BY子句的函数,以根据元素的值对数组进行分组。

grouparrayby(path,groupingElementName,groupedElementName)

输入:

{
  "Forest": [
    {
      "type": "Mammal",
      "qty": 1,
      "name": "Hippo"
    },
    {
      "type": "Bird",
      "qty": 2,
      "name": "Sparrow"
    },
    {
      "type": "Amphibian",
      "qty": 300,
      "name": "Lizard"
    },
    {
      "type": "Bird",
      "qty": 3,
      "name": "Parrot"
    },
    {
      "type": "Mammal",
      "qty": 1,
      "name": "Elephant"
    },
    {
      "type": "Mammal",
      "qty": 10,
      "name": "Dog"
    }   
  ]
}

转换器:

{
  "Result": "#grouparrayby($.Forest,type,all)"
}

输出:

{ 
   "Result":[ 
      { 
         "type":"Mammal",
         "all":[ 
            { 
               "qty":1,
               "name":"Hippo"
            },
            { 
               "qty":1,
               "name":"Elephant"
            },
            { 
               "qty":10,
               "name":"Dog"
            }
         ]
      },
      { 
         "type":"Bird",
         "all":[ 
            { 
               "qty":2,
               "name":"Sparrow"
            },
            { 
               "qty":3,
               "name":"Parrot"
            }
         ]
      },
      { 
         "type":"Amphibian",
         "all":[ 
            { 
               "qty":300,
               "name":"Lizard"
            }
         ]
      }
   ]
}

您可以使用多个分组元素进行分组。它们应该用冒号(:)分隔。

考虑以下输入:

{
  "Vehicle": [
    {
      "type": "air",
      "company": "Boeing",
      "name": "airplane"
    },
    {
      "type": "air",
      "company": "Concorde",
      "name": "airplane"
    },
    {
      "type": "air",
      "company": "Boeing",
      "name": "Chopper"
    },
    {
      "type": "land",
      "company": "GM",
      "name": "car"
    },
    {
      "type": "sea",
      "company": "Viking",
      "name": "ship"
    },
    {
      "type": "land",
      "company": "GM",
      "name": "truck"
    }
  ] 
}

转换器:

{
  "Result": "#grouparrayby($.Vehicle,type:company,all)"
}

输出:

{ 
   "Result":[ 
      { 
         "type":"air",
         "company":"Boeing",
         "all":[ 
            { 
               "name":"airplane"
            },
            { 
               "name":"Chopper"
            }
         ]
      },
      { 
         "type":"air",
         "company":"Concorde",
         "all":[ 
            { 
               "name":"airplane"
            }
         ]
      },
      { 
         "type":"land",
         "company":"GM",
         "all":[ 
            { 
               "name":"car"
            },
            { 
               "name":"truck"
            }
         ]
      },
      { 
         "type":"sea",
         "company":"Viking",
         "all":[ 
            { 
               "name":"ship"
            }
         ]
      }
   ]
}

调用自定义函数

您可以在C#中创建自己的自定义函数,并从转换器JSON中调用它们。
自定义函数必须驻留在public 类中,并且必须是public static方法。

使用以下语法调用自定义函数:

#customfunction(dll name, FQN for the static function, argument1.......,argumentN)

考虑以下输入:

{
  "tree": {
    "branch": {
      "leaf": "green",
      "flower": "red",
      "bird": "crow"
    }
  }
}

转换器:

{
  "Season": "#customfunction(JUST.NET.Test,JUST.NET.Test.Season.findseason,
             #valueof($.tree.branch.leaf),#valueof($.tree.branch.flower))"
}

自定义功能:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace JUST.NET.Test
{
    public class Season
    {
        public static string findseason(string leafColour, string flowerColour)
        {
            if (leafColour == "green" && flowerColour == "red")
                return "summer";
            else
                return "winter";
        }
    }
}

输出:

{"Season":"summer"}

函数嵌套

您可以轻松地嵌套函数以执行复杂的转换。

以下示例演示了此类转换的示例:

考虑以下输入:

{
  "Name": "Kari",
  "Surname": "Nordmann",
  "MiddleName": "Inger",
  "ContactInformation": "Karl johans gate:Oslo:88880000" ,
  "PersonalInformation": "45:Married:Norwegian"
}

转换器:

{
  "FullName": "#concat(#concat
  (#concat(#valueof($.Name), ),#concat(#valueof($.MiddleName), )),#valueof($.Surname))",
  "Contact Information": {
    "Street Name": "#substring(#valueof($.ContactInformation),
    0,#firstindexof(#valueof($.ContactInformation),:))",
    "City": "#substring(#valueof($.ContactInformation),#add(#firstindexof
    (#valueof($.ContactInformation),:),1),#subtract(#subtract
    (#lastindexof(#valueof($.ContactInformation),:),#firstindexof
    (#valueof($.ContactInformation),:)),1))",
    "PhoneNumber": "#substring
    (#valueof($.ContactInformation),#add(#lastindexof
    (#valueof($.ContactInformation),:),1),#subtract
    (#lastindexof(#valueof($.ContactInformation),),#lastindexof
    (#valueof($.ContactInformation),:)))"
  },
  "Personal Information": {
    "Age": "#substring(#valueof($.PersonalInformation),
    0,#firstindexof(#valueof($.PersonalInformation),:))",
    "Civil Status": "#substring(#valueof
    ($.PersonalInformation),#add(#firstindexof
    (#valueof($.PersonalInformation),:),1),#subtract(#subtract
    (#lastindexof(#valueof($.PersonalInformation),:),#firstindexof
    (#valueof($.PersonalInformation),:)),1))",
    "Ethnicity": "#substring(#valueof
    ($.PersonalInformation),#add(#lastindexof
    (#valueof($.PersonalInformation),:),1),#subtract(#lastindexof
    (#valueof($.PersonalInformation),),#lastindexof
    (#valueof($.PersonalInformation),:)))"
  }

输出:

{
   "FullName":"Kari Inger Nordmann",
   "Contact Information":{
     "Street Name":"Karl johans gate",
     "City":"Oslo",
     "PhoneNumber":"88880000"
    },
   "Personal Information":{
     "Age":"45",
     "Civil Status":"Married",
     "Ethnicity":"Norwegian"
    }
}

多个参数和常量函数

上述场景中的转换看起来相当复杂。当string变得更长时,它会变得非常混乱。此外,由于逗号(,)是保留关键字,因此无法将逗号连接到string

因此,引入了以下3个函数:

  • xconcat(string1,string2......stringx)——连接多个strings
  • xadd(int1,int2......intx)——添加多个整数
  • constant_comma() ——返回逗号(,)
  • constant_hash() ——返回哈希(#)

考虑以下输入:

{
  "Name": "Kari",
  "Surname": "Nordmann",
  "MiddleName": "Inger",
  "ContactInformation": "Karl johans gate:Oslo:88880000" ,
  "PersonalInformation": "45:Married:Norwegian"
}

转换器:

{
  "FullName": "#xconcat(#valueof($.Name),
  #constant_comma(),#valueof($.MiddleName),
               #constant_comma(),#valueof($.Surname))",
  "AgeOfParents": 
  "#xadd(#valueof($.AgeOfMother),#valueof($.AgeOfFather))"
}

输出:

{"FullName":"Kari,Inger,Nordmann",
"AgeOfParents":"67"}

检查是否存在

添加了以下两个函数来检查是否存在:

  • exists(path)
  • existsandnotempty(path)

考虑以下输入:

{
   "BuyDate": "2017-04-10T11:36:39+03:00",
   "ExpireDate": ""
}

转换器:

{
  "BuyDateString": "#ifcondition(#exists($.BuyDate),
  true,#concat(Buy Date : ,#valueof($.BuyDate)),NotExists)",
  "BuyDateString2": "#ifcondition(#existsandnotempty($.BuyDate),
  true,#concat(Buy Date : ,#valueof($.BuyDate)),EmptyOrNotExists)",
  "ExpireDateString": "#ifcondition(#exists($.ExpireDate),
  true,#concat(Expire Date : ,#valueof($.ExpireDate)),NotExists)",
  "ExpireDateString2": "#ifcondition(#existsandnotempty($.ExpireDate),
  true,#concat(Expire Date : ,#valueof($.ExpireDate)),EmptyOrNotExists)",
  "SellDateString": "#ifcondition(#exists($.SellDate),
  true,#concat(Sell Date : ,#valueof($.SellDate)),NotExists)",
  "SellDateString2": "#ifcondition(#existsandnotempty($.SellDate),
  true,#concat(Sell Date : ,#valueof($.SellDate)),EmptyOrNotExists)"
}

输出:

{
   "BuyDateString":"Buy Date : 2017-04-10T11:36:39+03:00",
   "BuyDateString2":"Buy Date : 2017-04-10T11:36:39+03:00",
   "ExpireDateString":"Expire Date : ",
   "ExpireDateString2":"EmptyOrNotExists",
   "SellDateString":"NotExists",
   "SellDateString2":"EmptyOrNotExists"
}

条件转换

使用ifgroup 函数可以实现条件转换。

该函数将表达式作为参数,该值应该计算为布尔值。

考虑以下输入:

{
  "Tree": {   
    "Branch": "leaf",
    "Flower": "Rose"
  }
}

转换器:

{
  "Result": {
    "Header": "JsonTransform",
    "#ifgroup(#exists($.Tree.Branch))": {
      "State": {
        "Value1": "#valueof($.Tree.Branch)",
        "Value2": "#valueof($.Tree.Flower)"
      }
    }
 }
}

输出:

{ 
   "Result":{ 
      "Header":"JsonTransform",
      "State":{ 
         "Value1":"leaf",
         "Value2":"Rose"
      }
   }
}

现在,对于相同的输入,如果我们使用以下转换器,我们会得到不同的输出。

转换器:

{
  "Result": {
    "Header": "JsonTransform",
    "#ifgroup(#exists($.Tree.Root))": {
      "State": {
        "Value1": "#valueof($.Tree.Branch)",
        "Value2": "#valueof($.Tree.Flower)"
      }
    }
 }
}

输出:

{ 
   "Result":{ 
      "Header":"JsonTransform"
   }
}

动态属性

我们现在可以使用eval 函数创建动态属性。该函数将表达式作为参数。

考虑以下输入:

{
  "Tree": {   
    "Branch": "leaf",
    "Flower": "Rose"
  }
}

转换器:

{
  "Result": {
      "#eval(#valueof($.Tree.Flower))": "x"
  }
}

输出:

{ 
   "Result":{ 
      "Rose":"x"
   }
}

使用前缀针对多个模式的模式验证

在新的Nuget 2.0.XX中引入了一个新功能,用于针对多个模式验证JSON。这是为了使用XSD中的前缀启用基于名称空间的验证。

下面是一个示例代码,您需要编写该代码以使用前缀来针对2个模式验证JSON

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

using JUST;
using System.IO;

namespace JUST.Test
{
    public class Program
    {
        public static void Main(string[] args)
        {
            string inputJson = File.ReadAllText("ValidationInput.json")//read input from JSON file.;
            string schemaJsonX = File.ReadAllText("SchemaX.json")//read first schema from JSON file.;
            string schemaJsonY = File.ReadAllText("SchemaY.json")//read second input from JSON file.;

            JsonValidator validator = new JsonValidator(inputJson)//create instance 
                                                        //of JsonValidator using the input.;
            validator.AddSchema("x", schemaJsonX)//Add first schema with prefix 'x'.;
            validator.AddSchema("y", schemaJsonY)//Add second schema with prefix 'y'.;

            validator.Validate();

        }
    }
}

在上述情况下,如果验证不成功,将引发验证错误的异常。

考虑验证输入:

{
  "x.tree": { "x.branch": { "x.leaf": "1" } },
  "x.child": 1,
  "y.animal": 1
}

模式X JSON

{
  "properties": {
    "tree": {
      "type": "object",
      "properties": {
        "branch": {
          "type": "object",
          "properties": {
            "leaf": { "type": "string" }
          }
        }
      }
    },
    "child": { "type": "string" }
  }
}

模式Y JSON

{
  "properties": {
    "animal": { "type": "string" }
  }
}

上述情况中抛出的异常消息是:

Unhandled Exception: System.Exception: Invalid type. Expected String but got Integer. 
Path '['x.child']', line 3, position 14. AND Invalid type. Expected String but got Integer. 
Path '['y.animal']', line 4, position 15.

基于数组令牌将JSON拆分为多个JSON(s)

现在可以将包含数组的JSON文件拆分为多个JSON文件,每个文件代表每个数组元素的文件。

为此目的增加了两个新功能:

  • public static IEnumerable<string> SplitJson(string input,string arrayPath)
  • public static IEnumerable<JObject> SplitJson(JObject input, string arrayPath)

考虑输入:

{
  "cars": {
    "Ford": [
      {
        "model": "Taurus",
        "doors": 4
      },
      {
        "model": "Escort",
        "doors": 4
      },
      {
        "model": "Fiesta",
        "doors": 3
      },
      {
        "model": "Bronco",
        "doors": 5
      }
    ],
    "firstName": "John",
    "lastName": "Smith",
  }
}

下面是一个示例代码,它分割了上面的输入:

string input = File.ReadAllText("Input.json");
List<string> outputs = JsonTransformer.SplitJson(input, "$.cars.Ford").ToList<string>();

输出将包含4JSON文件:

string input = File.ReadAllText("Input.json");
List<string> outputs = JsonTransformer.SplitJson(input, "$.cars.Ford").ToList<string>();
{"cars":{"Ford":{"model":"Escort",
"doors":4},"firstName":"John","lastName":"Smith"}}
{"cars":{"Ford":{"model":"Fiesta",
"doors":3},"firstName":"John","lastName":"Smith"}}
{"cars":{"Ford":{"model":"Bronco",
"doors":5},"firstName":"John","lastName":"Smith"}}

 JSON转换为其他数据格式

JUST.NET现在也可以将JSON数据转换为其他通用格式。此特征支持除BULK FUNCTIONS 以外的所有函数。

#loop函数接受一个额外的参数,该参数定义各个记录之间的分隔符。

#loop(path,seaperator).

如果未定义分隔符,则使用默认分隔符NEWLINE

已为此新功能引入了一个名为DataTransformer 的新类。

JSONXML的示例

JSON转换为XML的示例代码:

string input = File.ReadAllText("Input.json");
string transformer = File.ReadAllText("DataTransformer.xml");
string transformedString = DataTransformer.Transform(transformer, input);

Input.json

{
  "menu": {
    "id": {
      "file": "csv"
    },
    "value": {
      "Window": "popup"
    },
    "popup": {
      "menuitem": [
        {
          "value": "New",
          "onclick": {
            "action": "CreateNewDoc()"
          }
        },
        {
          "value": "Open",
          "onclick": "OpenDoc()"
        },
        {
          "value": "Close",
          "onclick": "CloseDoc()"
        }
      ]
    }
  },
  "x": [
    {
      "v": {
        "a": "a1,a2,a3",
        "b": "1",
        "c": "10"
      }
    },
    {
      "v": {
        "a": "b1,b2",
        "b": "2",
        "c": "20"
      }
    },
    {
      "v": {
        "a": "c1,c2,c3",
        "b": "3",
        "c": "30"
      }
    }
  ],
  "stringref": "thisisandveryunuasualandlongstring",
  "d": [ "one", "two", "three" ],
  "numbers": [ "1", "2", "3", "4", "5" ],
  "tree": {
    "branch": {
      "leaf": "green",
      "flower": "red",
      "bird": "crow"
    }
  },
  "Name": "Kari",
  "Surname": "Nordmann",
  "MiddleName": "Inger",
  "ContactInformation": "Karl johans gate:Oslo:88880000",
  "PersonalInformation": "45:Married:Norwegian",
  "AgeOfMother": "67",
  "AgeOfFather": "70",
  "BuyDate": "2017-04-10T11:36:39+03:00",
  "ExpireDate": "",
  "LogId": 5000510625
}

DataTransformer.xml

<?xml version="1.0" encoding="UTF-8" ?>
<root>
  <root>
    <ifconditiontesttrue>#ifcondition(#valueof($.menu.id.file),csv,
               #valueof($.menu.value.Window),fail)</ifconditiontesttrue>
    <ifconditiontestfalse>#ifcondition(#valueof($.menu.id.file),xml,
               #valueof($.menu.value.Window),fail)</ifconditiontestfalse>
    <stringresult>
      <lastindexofand>#lastindexof(#valueof($.stringref),and)</lastindexofand>
      <firstindexofand>#firstindexof(#valueof($.stringref),and)</firstindexofand>
      <subsrting>#substring(#valueof($.stringref),8,10)</subsrting>
      <concat>#concat(#valueof($.menu.id.file),#valueof($.menu.value.Window))</concat>
    </stringresult>
    <mathresult>
      <add>#add(#valueof($.numbers[0]),3)</add>
      <subtract>#subtract(#valueof($.numbers[4]),#valueof($.numbers[0]))</subtract>
      <multiply>#multiply(2,#valueof($.numbers[2]))</multiply>
      <divide>#divide(9,3)</divide>
    </mathresult>
    <conacted>#concatall(#valueof($.d))</conacted>
    <sum>#sum(#valueof($.numbers))</sum>
    <avg>#average(#valueof($.numbers))</avg>
    <min>#min(#valueof($.numbers))</min>
    <max>#max(#valueof($.numbers))</max>
    <arrayconacted>#concatallatpath(#valueof($.x),$.v.a)</arrayconacted>
    <arraysum>#sumatpath(#valueof($.x),$.v.c)</arraysum>
    <arrayavg>#averageatpath(#valueof($.x),$.v.c)</arrayavg>
    <arraymin>#minatpath(#valueof($.x),$.v.b)</arraymin>
    <arraymax>#maxatpath(#valueof($.x),$.v.b)</arraymax>
  </root>
  <FullName>#concat(#concat(#concat(#valueof($.Name), ),
  #concat(#valueof($.MiddleName), )),#valueof($.Surname))</FullName>
  <Contact_Information>
    <City>#substring(#valueof($.ContactInformation),#add(#firstindexof
    (#valueof($.ContactInformation),:),1),
    #subtract(#subtract(#lastindexof(#valueof($.ContactInformation),:),
    #firstindexof(#valueof($.ContactInformation),:)),1))</City>
    <PhoneNumber>#substring(#valueof($.ContactInformation),
    #add(#lastindexof(#valueof($.ContactInformation),:),1),
    #subtract(#lastindexof(#valueof($.ContactInformation),),
    #lastindexof(#valueof($.ContactInformation),:)))</PhoneNumber>
    <Street_Name>#substring(#valueof($.ContactInformation),0,
    #firstindexof(#valueof($.ContactInformation),:))</Street_Name>
  </Contact_Information>
  <Personal_Information>
    <Age>#substring(#valueof($.PersonalInformation),0,
    #firstindexof(#valueof($.PersonalInformation),:))</Age>
    <Ethnicity>#substring(#valueof($.PersonalInformation),
    #add(#lastindexof(#valueof($.PersonalInformation),:),1),
    #subtract(#lastindexof(#valueof($.PersonalInformation),),
    #lastindexof(#valueof($.PersonalInformation),:)))</Ethnicity>
    <LogId>#valueof($.LogId)</LogId>
    <Civil_Status>#substring(#valueof($.PersonalInformation),
    #add(#firstindexof(#valueof($.PersonalInformation),:),1),
    #subtract(#subtract(#lastindexof(#valueof($.PersonalInformation),:),
    #firstindexof(#valueof($.PersonalInformation),:)),1))</Civil_Status>
  </Personal_Information>
  <Custom>#customfunction(JUST.NET.Test,JUST.NET.Test.Season.findseason,
  #valueof($.tree.branch.leaf),#valueof($.tree.branch.flower))</Custom>
  <iteration>
    "#loop($.numbers,<!--Record ends here-->)": {
    <Record>
      <CurrentValue>#currentvalue()</CurrentValue>
      <CurrentIndex>#currentindex()</CurrentIndex>
      <IsLast>#ifcondition(#currentindex(),#lastindex(),yes,no)</IsLast>
      <LastValue>#lastvalue()</LastValue>
      <SomeValue>#valueof($.LogId)</SomeValue>
    </Record>}
  </iteration> 
</root>

输出:

<?xml version="1.0" encoding="UTF-8" ?>
<root>
  <root>
    <ifconditiontesttrue>popup</ifconditiontesttrue>
    <ifconditiontestfalse>fail</ifconditiontestfalse>
    <stringresult>
      <lastindexofand>21</lastindexofand>
      <firstindexofand>6</firstindexofand>
      <subsrting>dveryunuas</subsrting>
      <concat>csvpopup</concat>
    </stringresult>
    <mathresult>
      <add>4</add>
      <subtract>4</subtract>
      <multiply>6</multiply>
      <divide>3</divide>
    </mathresult>
    <conacted>onetwothree</conacted>
    <sum>15</sum>
    <avg>3</avg>
    <min>1</min>
    <max>5</max>
    <arrayconacted>a1,a2,a3b1,b2c1,c2,c3</arrayconacted>
    <arraysum>60</arraysum>
    <arrayavg>20</arrayavg>
    <arraymin>1</arraymin>
    <arraymax>3</arraymax>
  </root>
  <FullName>Kari Inger Nordmann</FullName>
  <Contact_Information>
    <City>Oslo</City>
    <PhoneNumber>88880000</PhoneNumber>
    <Street_Name>Karl johans gate</Street_Name>
  </Contact_Information>
  <Personal_Information>
    <Age>45</Age>
    <Ethnicity>Norwegian</Ethnicity>
    <LogId>5000510625</LogId>
    <Civil_Status>Married</Civil_Status>
  </Personal_Information>
  <Custom>summer</Custom>
  <iteration>
    <Record>
      <CurrentValue>1</CurrentValue>
      <CurrentIndex>0</CurrentIndex>
      <IsLast>no</IsLast>
      <LastValue>5</LastValue>
      <SomeValue>5000510625</SomeValue>
    </Record><!--Record ends here-->
    <Record>
      <CurrentValue>2</CurrentValue>
      <CurrentIndex>1</CurrentIndex>
      <IsLast>no</IsLast>
      <LastValue>5</LastValue>
      <SomeValue>5000510625</SomeValue>
    </Record><!--Record ends here-->
    <Record>
      <CurrentValue>3</CurrentValue>
      <CurrentIndex>2</CurrentIndex>
      <IsLast>no</IsLast>
      <LastValue>5</LastValue>
      <SomeValue>5000510625</SomeValue>
    </Record><!--Record ends here-->
    <Record>
      <CurrentValue>4</CurrentValue>
      <CurrentIndex>3</CurrentIndex>
      <IsLast>no</IsLast>
      <LastValue>5</LastValue>
      <SomeValue>5000510625</SomeValue>
    </Record><!--Record ends here-->
    <Record>
      <CurrentValue>5</CurrentValue>
      <CurrentIndex>4</CurrentIndex>
      <IsLast>yes</IsLast>
      <LastValue>5</LastValue>
      <SomeValue>5000510625</SomeValue>
    </Record><!--Record ends here-->
  </iteration>
</root>

JSONCSV的示例

JSON转换为CSV的示例代码:

string transformer = File.ReadAllText("Input.json");
string transformer = File.ReadAllText("DataTransformer.csv");
string transformedString = DataTransformer.Transform(transformer, input);

输入文件与XML示例相同。

"#loop($.numbers)": {#currentvalue(),#currentindex(),
#ifcondition(#currentindex(),#lastindex(),yes,no),#lastvalue(),#valueof($.LogId)}

输出:

1,0,no,5,5000510625
2,1,no,5,5000510625
3,2,no,5,5000510625
4,3,no,5,5000510625
5,4,yes,5,5000510625

链接到测试源代码(源代码现在也可用)

我创建了一个包含C#项目的GitHub存储库,并在输入JSON文件上有各种转换方案。

我希望您可以使用JUST来转换JSON文档。

 

原文地址:https://www.codeproject.com/Articles/1187172/JUST-JSON-Under-Simple-Transformation

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值