【问题标题】:Scala: Create structure (XML) from Lists of ListsScala:从列表创建结构(XML)
【发布时间】:2011-04-14 20:27:43
【问题描述】:

我有一个来自 java 的结构,一个 List > 包含 像这样的元素:

[[ "Node0", "Node00", "Leaf0"],
 [ "Node0", "Node00", "Leaf1"],
 [ "Node1", "Leaf2"],
 [ "Node0", "Leaf3"],
 [ "Node2", "Node20", "Node200", "Leaf4"]]

我想做的是在 最简单的方法,以类似下面的方式结束。 我可以通过多种方式做到这一点,迭代、递归调用等。

对解决此问题的紧凑可读方式有什么建议吗?

<node> Node0 
      <node> Node00 
            <node> Leaf0 </node>
            <node> Leaf1 </node>
      </node>
      <node> Leaf3 </node>
</node>
<node> Node1
      <node> Leaf2 </node>
</node>
<node> Node2
      <node> Node20
            <node> Node200
                  <node> Leaf4 </node>
            </node>
      </node>
</node>

【问题讨论】:

  • 我建议更易读的 XML 输出表单将节点名称放在属性(或子元素)中,而不是将文本与其他子元素混合。例如。 &lt;node name="Node0"&gt; &lt;node name="Node00"&gt; 或 &lt;node&gt;&lt;name&gt;Node0&lt;/name&gt; &lt;node&gt;&lt;name&gt;Node00&lt;/name&gt;...&lt;/node&gt;&lt;/node&gt;
  • 如果列表以 Scala 语法提供会更有帮助。

标签: java xml list scala


【解决方案1】:

试试this answer,了解如何从 Scala 中的集合输出 XML。

另外,我建议更易读的 XML 输出表单将节点名称放在属性(或子元素)中,而不是将文本与其他子元素混合。例如

<node name="Node0">
  <node name="Node00">

或

<node>
  <name>Node0</name>
  <node>
    <name>Node00</name>
    ...
  </node>
</node> 

【讨论】:

    【解决方案2】:

    好的,我试了一下。正如其他人所建议的那样,我也在使用一个属性。对于将在列表内容之后生成元素 named 的版本,而不是使用属性,还有几行注释。

    这项工作的困难部分由下面的类完成,它接受一个字符串列表并转换给定给它的节点,以便它们包含列表表示的节点层次结构。

    import xml._
    import transform._
    
    class AddPath(l: List[String]) extends RewriteRule {
      def listToNodes(l: List[String]): Seq[Node] = l match {
        case Nil => Seq.empty
        case first :: rest => 
          <node>{listToNodes(rest)}</node> % Attribute("name", Text(first), Null)
        //case first :: rest => 
          //<node>{listToNodes(rest)}</node> copy (label =  first)
      }
    
      def transformChild(child: Seq[Node]) = l match {
        case Nil => child
        case first :: rest =>
          child flatMap {
            case elem: Elem if elem.attribute("name") exists (_ contains Text(first)) =>
            //case elem: Elem if elem.label == first =>
              new AddPath(rest) transform elem
            case other => Seq(other)
          }
      }
    
      def appendToOrTransformChild(child: Seq[Node]) = {
        val newChild = transformChild(child)
        if (newChild == child)
          child ++ listToNodes(l)
        else
          newChild
      }
    
      override
      def transform(n: Node): Seq[Node] = n match {
        case elem: Elem => elem.copy(child = appendToOrTransformChild(elem.child))
        case other => other
      }
    }
    

    在这之后事情变得非常简单。首先,我们创建列表,然后从中生成规则列表。

    val listOfStrings = List(List("Node0", "Node00", "Leaf0"),
                             List("Node0", "Node00", "Leaf1"),
                             List("Node1", "Leaf2"),
                             List("Node0", "Leaf3"),
                             List("Node2", "Node20", "Node200", "Leaf4"))
    val listOfAddPaths = listOfStrings map (new AddPath(_))
    

    接下来,我们根据这些规则创建一个规则转换器。

    val ruleTransformer = new RuleTransformer(listOfAddPaths: _*)
    

    最后,我们创建 XML 并漂亮地打印它。请注意,我正在添加一个根节点。如果您不想要它,只需获取它的child。另请注意,ruleTransformer 将返回一个带有单个节点的Seq[Node]——我们的结果。

    val results = ruleTransformer(<root/>)
    val prettyPrinter = new PrettyPrinter(80, 4)
    results foreach { xml =>
      println(prettyPrinter format xml)
    }
    

    还有输出:

    <root>
        <node name="Node0">
            <node name="Node00">
                <node name="Leaf0"></node>
                <node name="Leaf1"></node>
            </node>
            <node name="Leaf3"></node>
        </node>
        <node name="Node1">
            <node name="Leaf2"></node>
        </node>
        <node name="Node2">
            <node name="Node20">
                <node name="Node200">
                    <node name="Leaf4"></node>
                </node>
            </node>
        </node>
    </root>
    

    替代版本的输出:

    <root>
        <Node0>
            <Node00>
                <Leaf0></Leaf0>
                <Leaf1></Leaf1>
            </Node00>
            <Leaf3></Leaf3>
        </Node0>
        <Node1>
            <Leaf2></Leaf2>
        </Node1>
        <Node2>
            <Node20>
                <Node200>
                    <Leaf4></Leaf4>
                </Node200>
            </Node20>
        </Node2>
    </root>
    

    【讨论】:

    • 感谢您几乎史诗般的回答。我真的没想到有人会编写运行代码,只有指向正确方向的指针就可以了。非常感谢您的宝贵努力,我从中学到了很多。
    猜你喜欢
    • 2018-11-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多