Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/xpath/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何使用解构绑定将XML转换为特定的s表达式树?_Xml_Emacs_Elisp - Fatal编程技术网

如何使用解构绑定将XML转换为特定的s表达式树?

如何使用解构绑定将XML转换为特定的s表达式树?,xml,emacs,elisp,Xml,Emacs,Elisp,我面前有一个任务,其中有一个XML文档,我需要 以系统的方式将其转换为另一个XML文档-更改标记Foo 要标记栏,请将所有具有name=“frob”属性的Qux标记更改为frob标记, 等等我不知道如何使用XSLT,但我对自己说- 嘿,如果我必须对基于树的数据进行一系列转换, 这听起来像Lisp擅长的东西 因此,我有一块XML—例如: <Object> <field name="id">100520</field> <field name

我面前有一个任务,其中有一个XML文档,我需要 以系统的方式将其转换为另一个XML文档-更改标记Foo 要标记栏,请将所有具有
name=“frob”
属性的Qux标记更改为frob标记, 等等我不知道如何使用XSLT,但我对自己说- 嘿,如果我必须对基于树的数据进行一系列转换, 这听起来像Lisp擅长的东西

因此,我有一块XML—例如:

<Object>
    <field name="id">100520</field>
    <field name="type_id">77</field>
    <field name="has_extras"></field>
    <field name="author_id">7</field>
    <field name="summary">To Sir Duke, with love</field>
</Object>
我很难想出如何对付那棵树,让它进入森林 我想要的形状。我目前的尝试是脆弱的-在
assoc
cxr
功能。CL的
解构绑定
似乎是我想要的,但我 不知道如何应用它。我正试图改变上述结构 为此:

(Object
  (id "100520")
  (type_id "77")
  (has_extras "")
  (author_id "7")
  (summary "To Sir Duke, with love"))
  • 解构绑定
    真的是我需要的工具吗
  • 如果是这样的话,我应该如何应用它来从我的数据的一个形状到另一个形状
  • 如果没有,什么是正确的工具

确实,
解构绑定
不能胜任这项工作,但在Emacs 24中,您可以使用
pcase
模式匹配宏非常简洁地完成这项工作,如下所示:

(require 'cl)                ;; for `mapcan'
(require 'pcase)

(defun xslt-in-elisp (xml)
  (pcase xml
    (`(Object . ,rest)
     `(Object . ,(mapcan #'xslt-in-elisp rest)))

    (`(field ((name . ,name)))
     `((,(intern name) "")))

    (`(field ((name . ,name)) ,value)
     `((,(intern name) ,value)))

    (_ nil)))

(xslt-in-elisp
 '(Object nil "\n        "
          (field ((name . "id")) "100520")
          "\n        "
          (field
           ((name . "type_id"))
           "77")
          "\n        "
          (field
           ((name . "has_extras")))
          "\n        "
          (field
           ((name . "author_id"))
           "7")
          "\n        "
          (field
           ((name . "summary"))
           "To Sir Duke, with love")
          "\n    "))
评估结果如下:

(Object
 (id "100520")
 (type_id "77")
 (has_extras "")
 (author_id "7")
 (summary "To Sir Duke, with love"))
工作原理:
pcase
获取一个值进行模式匹配,并按顺序尝试一系列子句
(模式值)
。您可以使用
M-x descripe函数pcase
查找详细信息,但基本上模式看起来与您希望它们匹配的模式相似,使用反引号语法指定哪些部分是要绑定的模式匹配变量,哪些部分作为文字符号匹配。那么,第一条规则

`(Object . ,rest)
Object
作为第一个符号匹配任何列表,并将变量
rest
绑定到任何剩余元素。规则

`(field ((name . ,name))` 
为带有名称但没有内容的
字段
标记匹配S-exp(如示例中的
有额外的内容)。等等最后一条规则,
\uu
,对于与这些规则不匹配的任何内容,都返回
nil
。每个规则的右侧可以是任何Lisp表达式。对于这种类型的转换,最有用的是使用backquote和unquote,这样做的好处是模板看起来就像它们匹配的规则一样

唯一稍微棘手的部分是如何累积
(Object…
的子节点的转换值。如果我们使用
mapcar
对它们进行迭代,我们最终会得到不需要的
nil
s,其中最初有字符串空白和其他垃圾。解决方案是让
字段
标记的规则返回一个单元素列表,并使用
cl
包中的
mapcan
将这些单元素列表连接在一起。垃圾元素如
nil
和空格字符串正好匹配
规则,因此它们被转换为空列表并从结果中消失


我将transformer作为递归函数编写,但是为了健壮性,您可以很容易地将它拆分为只匹配
(Object…
sexps)的顶级transformer和只匹配
(field…
sexps)的单独transformer

确实,
解构绑定
不能胜任这项工作,但在Emacs 24中,您可以使用
pcase
模式匹配宏非常简洁地完成这项工作,如下所示:

(require 'cl)                ;; for `mapcan'
(require 'pcase)

(defun xslt-in-elisp (xml)
  (pcase xml
    (`(Object . ,rest)
     `(Object . ,(mapcan #'xslt-in-elisp rest)))

    (`(field ((name . ,name)))
     `((,(intern name) "")))

    (`(field ((name . ,name)) ,value)
     `((,(intern name) ,value)))

    (_ nil)))

(xslt-in-elisp
 '(Object nil "\n        "
          (field ((name . "id")) "100520")
          "\n        "
          (field
           ((name . "type_id"))
           "77")
          "\n        "
          (field
           ((name . "has_extras")))
          "\n        "
          (field
           ((name . "author_id"))
           "7")
          "\n        "
          (field
           ((name . "summary"))
           "To Sir Duke, with love")
          "\n    "))
评估结果如下:

(Object
 (id "100520")
 (type_id "77")
 (has_extras "")
 (author_id "7")
 (summary "To Sir Duke, with love"))
工作原理:
pcase
获取一个值进行模式匹配,并按顺序尝试一系列子句
(模式值)
。您可以使用
M-x descripe函数pcase
查找详细信息,但基本上模式看起来与您希望它们匹配的模式相似,使用反引号语法指定哪些部分是要绑定的模式匹配变量,哪些部分作为文字符号匹配。那么,第一条规则

`(Object . ,rest)
Object
作为第一个符号匹配任何列表,并将变量
rest
绑定到任何剩余元素。规则

`(field ((name . ,name))` 
为带有名称但没有内容的
字段
标记匹配S-exp(如示例中的
有额外的内容)。等等最后一条规则,
\uu
,对于与这些规则不匹配的任何内容,都返回
nil
。每个规则的右侧可以是任何Lisp表达式。对于这种类型的转换,最有用的是使用backquote和unquote,这样做的好处是模板看起来就像它们匹配的规则一样

唯一稍微棘手的部分是如何累积
(Object…
的子节点的转换值。如果我们使用
mapcar
对它们进行迭代,我们最终会得到不需要的
nil
s,其中最初有字符串空白和其他垃圾。解决方案是让
字段
标记的规则返回一个单元素列表,并使用
cl
包中的
mapcan
将这些单元素列表连接在一起。垃圾元素如
nil
和空格字符串正好匹配
规则,因此它们被转换为空列表并从结果中消失


我将transformer作为递归函数编写,但是为了健壮性,您可以很容易地将它拆分为只匹配
(Object…
sexps)的顶级transformer和只匹配
(field…
sexps)的单独transformer

如果XSLT是一个选项,我会认真地推荐它来完成这项任务。你可以通过一个非常简洁的转换来实现你所描述的,然后去喝杯啤酒。为了更直接地回答您的问题,我不认为
解构bind
,或emacs lisp是您需要的工具。我很害怕。我不太担心学习XSLT,而是担心在最后期限内学习XSLT。我的想法是“好的