在YAML中构建简单的层次结构

时间:2020-08-24 20:42:21

标签: yaml

我正在尝试做我认为在YAML中简单的事情。这是具有重复元素的简单层次结构。下面的第一个示例非常接近,但是每个 node 序列元素都会触发错误:“序列条目缩进不良”。我看不出有什么问题。

请注意,我在下面提供了一个可行的示例,但是它使用的唯一键不是我想要的。

- agegrp: 1 
  - node      : "(14, 6)"
    # id: "(14, 6)"
    - branch  : "to 7"
      id      : "to 7"
      tocond  : 7
      pr      : 1.0
      next    : (0, 0)
  - node      : "(14, 7)"
      # id: "(14,7)" 
    - branch  : "to 7" 
      id      : "to 7"
      tocond  : 7 
      pr      : 0.85 
      next    : (0, 0) 
    - branch  : "to 8" 
      id      : "to 8"
      tocond  : 8
      pr      :  0.15
      next    : (4, 4)
- agegrp      : 2 
  - node      : "(14, 6)"
    # id: "(14, 6)"
    - branch  : "to 7"
      id      : "to 7"
      tocond  : 7
      pr      : 1.0
      next    : (0, 0)
  - node      : "(14, 7)"
      # id: "(14,7)" 
    - branch  : "to 7" 
      id      : "to 7"
      tocond  : 7 
      pr      : 0.85 
      next    : (0, 0) 
    - branch  : "to 8" 
      id      : "to 8"
      tocond  : 8
      pr      :  0.15
      next    : (4, 4)

请注意以下内容有效,但是我不希望分支和节点具有唯一的名称。我想要一个重复的结构。我可以在分支和节点的前面使用破折号,但这会导致另一个问题:序列条目的缩进错误。

agegrp:
id: 1
node (14, 6): 
  # id: "(14, 6)"
  branch: 
    id: "to 7"
    tocond: 7
    pr: 1.0
    next: (0, 0)
node (14,7): 
  # id: "(14,7)" 
  branch to 7: 
    id: "to 7"
    tocond: 7 
    pr: 0.85 
    next: (0, 0) 
  branch to 8: 
    id: "to 8"
    tocond: 8
    pr:  0.15
    next: (4, 4)

将有5个年龄段。节点在年龄组内。分支在节点内。每个分支都有3个属性。我可以在每个节点下放置一个id项目,而不是上面显示的那样。

我对于何时必须使用前导破折号感到困惑,何时不可以使用。我对何时允许值以及何时不允许值感到困惑。

在YAML中甚至有可能吗? TOML不喜欢层次结构。到目前为止,我已经将其保存在csv中并进行了解析,并在代码中构建了一个字典。我以为我可以使用本来可以代表层次结构的格式。

我想要的输出:

  • 年龄数组或字典。永远不会超过10个,并且数组就可以了。
  • 每个年龄段的节点数决定
  • 对于每个节点,分支的数组或字典

这里是一个例子:这是一个针对年龄段的字典:

(1, 1) =>
   CovidSim.Branch(5, 5, 0.2, (2, 1), "nil", "nil")
   CovidSim.Branch(5, 6, 0.65, (2, 2), "nil", "mild")
   CovidSim.Branch(5, 7, 0.15, (2, 3), "nil", "sick")
(2, 1) =>
   CovidSim.Branch(5, 3, 0.8, (0, 0), "nil", "recovered")
   CovidSim.Branch(5, 7, 0.2, (3, 3), "nil", "sick")
(2, 2) =>
   CovidSim.Branch(6, 6, 1.0, (3, 2), "mild", "mild")
(2, 3) =>
   CovidSim.Branch(7, 7, 0.85, (3, 3), "sick", "sick")
   CovidSim.Branch(7, 8, 0.15, (3, 4), "sick", "severe")
(3, 2) =>
   CovidSim.Branch(6, 3, 1.0, (0, 0), "mild", "recovered")
(3, 3) =>
   CovidSim.Branch(7, 3, 0.8, (0, 0), "sick", "recovered")
   CovidSim.Branch(7, 7, 0.1, (5, 3), "sick", "sick")
   CovidSim.Branch(7, 8, 0.1, (4, 4), "sick", "severe")
(3, 4) =>
   CovidSim.Branch(8, 3, 0.45, (0, 0), "severe", "recovered")
   CovidSim.Branch(8, 8, 0.5, (4, 4), "severe", "severe")
   CovidSim.Branch(8, 4, 0.05, (0, 5), "severe", "dead")
(4, 4) =>
   CovidSim.Branch(8, 3, 0.85, (0, 0), "severe", "recovered")
   CovidSim.Branch(8, 8, 0.1, (5, 4), "severe", "severe")
   CovidSim.Branch(8, 4, 0.05, (0, 5), "severe", "dead")
(5, 3) =>
   CovidSim.Branch(7, 3, 0.9, (0, 0), "sick", "recovered")
   CovidSim.Branch(7, 4, 0.1, (0, 5), "sick", "dead")
(5, 4) =>
   CovidSim.Branch(8, 3, 0.6, (0, 0), "severe", "recovered")
   CovidSim.Branch(8, 4, 0.4, (0, 5), "severe", "dead")

外部容器是5个年龄段字典的数组。

(请注意,此示例在我要减少的每个分支中都包含一些额外的字段。)

谢谢!

3 个答案:

答案 0 :(得分:2)

如果您查看YAML spec的收藏夹

YAML的阻止集合使用缩进范围,并开始每个 单独输入。

块顺序用破折号表示每个条目 和空格(“-”)。

映射使用冒号和空格(“:”)标记每个 键:值对。

注释以八齿形(也称为a “哈希”,“清晰”,“磅”或“数字符号”-“#”)。

所以你

- agegrp: 1 

是序列和图谱的融合

您可以这样做

--- 
- 
  id: 1
  nodes: 
    - 
      branches: 
        - 
          id: "to 7"
          next: "(0, 0)"
          pr: 1.0
          tocond: 7
        - 
          id: "to 7"
          next: "(0, 0)"
          pr: 0.85
          tocond: 7
        - 
          id: "to 8"
          next: "(4, 4)"
          pr: 0.15
          tocond: 8
      id: "(14, 6)"

如果这符合您的需求

答案 1 :(得分:1)

按照您自己的答案进行操作:YAML 确实允许您将实体名称放入YAML文件中。通过为标签提供语法来实现。这是一个文件外观示例:

!agegrp 4:
  !node [9,6]:
    - !branch
      tocond: 6
      next:
        - 14
        - 6
      pr: 1.0
  !node [9,5]:
    - !branch
      tocond: 3
      next:
        - 0
        - 0
      pr: 0.8
    - !branch
      tocond: 7
      next:
        - 14
        - 7
      pr: 0.2

请注意,我将YAML序列用于节点坐标,因为看起来您还是想将它们解析为数字对((9,6)会解析为字符串)。您可以保留原始语法。

这是将标记后的值直接与其关联。因此,4将被标记为!agegrp,序列[9,6]将被标记为!node,而包含tocond等的映射将被标记为!branch。这些本地标记是应用程序定义的;您将需要使用大多数YAML实现为它们注册处理程序。

从语义上讲,这会将4标记为 agegrp (无论是什么),而节点不属于该 agegrp 对象的一部分–使用此标记,只有键4被标记为 agegrp 。当然,如何处理文件取决于您。一种替代方法是:

4: !agegrp
  !node [9,6]:
    …

现在,包含节点的映射标记为 agegrp ,而4只是映射中的键(可能解析为整数)。

如果您希望ID成为对象的一部分,则可以将文档转换为基于序列的结构, @KeepCalmAndCarryOn 已经显示了执行此操作的常用方法,以下是使用标签的一种方法:

- !agegrp
  - !id 4
  - !node
    - !id [9,6]
    - !branch
      tocond: 6
      next:
        - 14
        - 6
      pr: 1.0
  - !node
    - !id [9,5]
    - !branch
      tocond: 3
      next:
        - 0
        - 0
      pr: 0.8
    - !branch
      tocond: 7
      next:
        - 14
        - 7
      pr: 0.2

这是为了平整 node 的内部结构,以便ID和分支可以处于同一级别。这要求加载代码在加载该YAML时正确区分!id!branch节点。这种结构经常用在XML中,它不提供像YAML那样的映射,因此,所有嵌套结构都是序列,并且不同的子代通过其元素名称来区分。

答案 2 :(得分:0)

感谢您的帮助。我并没有绕过YAML并创建没有任何名称的实体组。 @KeepCalmAndCarryOn:您的结构导致在同一级别上具有id项和branch项的节点数组(branch项是分支的数组,每个分支都是属性的字典。这有效,但不显示非常好并且更难使用(但肯定包含示例中的所有信息)。

我更喜欢严格的等级制度。我手动编码json。然后,将json解析为嵌套的julia对象:这样的字典数组:

async function fetchMessages() {
$.ajax({
    type: "POST",
    url: "../ASPX/bubblelandFetch.aspx",
    success: function (data) {
        console.log(data);
        data = JSON.parse(data);
        var container = document.getElementById("messages-container");
        var uid;
        container.innerHTML = "";

        console.log(data);

        for (var i in data) {
            var message = '<div id="' + data[i]["mid"];
            message += '" class="message ' + data[i]["color"] + '">';
            message += '<div class="profile-container">';

            if (data[i]["uid"] == "user")
                uid = "/Media/user"
            else
                uid = "/Media/Profile/" + data[i]["uid"];

            message += '<img src="' + uid + '.png"/>';
            message += '<span>' + data[i]["name"] + '</span></div>';
            message += '<div class="content">' + data[i]["content"] + '</div>';

            container.innerHTML += message;
        }
    },

    complete: function () {
        setTimeout(fetchMessages, intevral);
    }
});
}

输出被截断,但是您可以将每个年龄组视为一个键-以节点的格为其值。节点的每个字典显示第一个键(一个节点),并以分支数组作为其值。分支数组中的每个项目都是分支的每个属性的字段的决定。

一个agegrp看起来像这样:

Dict{String,Any} with 5 entries:
  "4" => Dict{String,Any}("(9,6)"=>Any[Dict{String,Any}("tocond"=>6,"next"=>Any…
  "1" => Dict{String,Any}("(9,6)"=>Any[Dict{String,Any}("tocond"=>6,"next"=>Any…
  "5" => Dict{String,Any}("(9,6)"=>Any[Dict{String,Any}("tocond"=>6,"next"=>Any…
  "2" => Dict{String,Any}("(9,6)"=>Any[Dict{String,Any}("tocond"=>6,"next"=>Any…
  "3" => Dict{String,Any}("(9,6)"=>Any[Dict{String,Any}("tocond"=>6,"next"=>Any…

然后,我将这个Julia嵌套对象(有点陈旧,但结构更清晰-至少对我来说),并通过YAML将其放置以创建有效的YAML输出。

这个YAML正是我真正想要的,即使对于正确使用YAML的人来说这似乎令人讨厌。这只是一个agegrp(其他结构相同,并且在YAML文档中依次执行):

Dict{String,Any} with 8 entries:
  "(9,6)"  => Any[Dict{String,Any}("tocond"=>6,"next"=>Any[14, 6],"pr"=>1.0)]
  "(9,5)"  => Any[Dict{String,Any}("tocond"=>3,"next"=>Any[0, 0],"pr"=>0.8), Di…
  "(14,6)" => Any[Dict{String,Any}("tocond"=>3,"next"=>Any[0, 0],"pr"=>1.0)]
  "(9,7)"  => Any[Dict{String,Any}("tocond"=>7,"next"=>Any[14, 7],"pr"=>0.85), …
  "(5,5)"  => Any[Dict{String,Any}("tocond"=>5,"next"=>Any[9, 5],"pr"=>0.2), Di…
  "(14,8)" => Any[Dict{String,Any}("tocond"=>3,"next"=>Any[0, 0],"pr"=>0.45), D…
  "(14,7)" => Any[Dict{String,Any}("tocond"=>3,"next"=>Any[0, 0],"pr"=>0.85), D…
  "(19,8)" => Any[Dict{String,Any}("tocond"=>3,"next"=>Any[0, 0],"pr"=>0.9), Di…

这遵循我想要的层次结构:

4:                     # the id of an agegrp
  (9,6):               # the id of a node
    - tocond: 6        # first property of a branch
      next:
        - 14
        - 6
      pr: 1.0
  (9,5):
    - tocond: 3
      next:
        - 0
        - 0
      pr: 0.8
    - tocond: 7
      next:
        - 14
        - 7
      pr: 0.2
  (14,6):
    - tocond: 3
      next:
        - 0
        - 0
      pr: 1.0
  (9,7):
    - tocond: 7
      next:
        - 14
        - 7
      pr: 0.85
    - tocond: 8
      next:
        - 14
        - 8
      pr: 0.15
  <rest of output truncated...>

我确实通过将实体名称(agegrp,节点,分支)与每个实体的特定实例的实际值混合在一起弄乱了自己—就像我试图用类型标记每个事物。您不会在字典中那样做。我在这里使用Julia,但Dicts本质上与Python中相同。

因此,对YAML的尝试有点令人沮丧。但是,它比我刚开始使用的CSV输入要容易得多,比手工编写JSON要容易得多。因此,成功的尝试!