如何使用解构绑定将XML转换为特定的s表达式树?
我面前有一个任务,其中有一个XML文档,我需要 以系统的方式将其转换为另一个XML文档-更改标记Foo 要标记栏,请将所有具有如何使用解构绑定将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
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。我的想法是“好的