能增加转成 markdown 格式的功能么
Closed this issue · 7 comments
mei-rune commented
能增加转成 markdown 格式的功能么
jan-bar commented
这个做起来应该简单(直接用递归一行行输出结果,控制前面缩进就行),主要是markdown的格式要什么样,还是说格式可以用参数指定。这块需要研究,你也可以提pr额。后面有空可以搞搞。
mei-rune commented
你看看行不行,行的话, 我再试增加新版本xmind的支持
From 75a38894c07754ae1349c55fc8645578c957f82a Mon Sep 17 00:00:00 2001
From: meifakun <runner.mei@gmail.com>
Date: Mon, 21 Aug 2023 22:11:01 +0800
Subject: [PATCH] add markdown convert
---
convert/markdown/markdown.go | 36 ++++++++++++++++++
markdown.go | 72 ++++++++++++++++++++++++++++++++++++
2 files changed, 108 insertions(+)
create mode 100644 convert/markdown/markdown.go
create mode 100644 markdown.go
diff --git a/convert/markdown/markdown.go b/convert/markdown/markdown.go
new file mode 100644
index 0000000..e8fef4c
--- /dev/null
+++ b/convert/markdown/markdown.go
@@ -0,0 +1,36 @@
+package main
+
+import (
+ "fmt"
+ "os"
+
+ "github.com/jan-bar/xmind"
+)
+
+// go run youdao.go test.mindmap test.xmind
+
+func main() {
+ if len(os.Args) != 3 {
+ return
+ }
+ book, err := xmind.LoadFile(os.Args[1])
+ if err != nil {
+ fmt.Println(err)
+ return
+ }
+
+ fw, err := os.Create(os.Args[2])
+ if err != nil {
+ fmt.Println(err)
+ return
+ }
+ //goland:noinspection GoUnhandledErrorResult
+ defer fw.Close()
+
+ err = book.SaveToMarkdown(fw)
+ if err != nil {
+ fmt.Println(err)
+ return
+ }
+}
+
diff --git a/markdown.go b/markdown.go
new file mode 100644
index 0000000..fc2728b
--- /dev/null
+++ b/markdown.go
@@ -0,0 +1,72 @@
+package xmind
+
+import (
+ "io"
+ "strings"
+)
+
+func (wk *WorkBook) ForEach(cb func(parents []*Topic, current *Topic) error) error {
+ for _, topic := range wk.Topics {
+ if err := topic.ForEach(nil, cb); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+func (st *Topic) ForEach(parents []*Topic, cb func([]*Topic, *Topic) error) error {
+ if st != nil {
+ var loop func([]*Topic, *Topic) error
+ loop = func(parents []*Topic, tp *Topic) error {
+ if tp != nil {
+ if err := cb(parents, tp); err != nil { // 通过回调函数让调用者实现自己的逻辑
+ return err
+ }
+ if tp.Children != nil && len(tp.Children.Attached) > 0 {
+ for _, tc := range tp.Children.Attached {
+ err := loop(append(parents, tp), tc)
+ if err != nil {
+ return err
+ }
+ }
+ }
+ }
+ return nil
+ }
+ if st.RootTopic != nil {
+ return loop(parents, st.RootTopic) // 当前为根节点,从中心主题开始遍历
+ } else {
+ return loop(parents, st) // 其他情况从当前节点开始遍历
+ }
+ }
+ return nil
+}
+
+func (wk *WorkBook) SaveToMarkdown(w io.Writer) error {
+ return wk.ForEach(func(parents []*Topic, current *Topic) error {
+ _, err := io.WriteString(w, strings.Repeat("#", len(parents)))
+ if err != nil {
+ return err
+ }
+ io.WriteString(" ")
+ io.WriteString(w,current.Title)
+ io.WriteString(w,"\r\n")
+ io.WriteString(w,"\r\n")
+ if len(current.Labels) > 0 {
+ for _, label := range current.Labels {
+ io.WriteString(w,"> ")
+ io.WriteString(w,label)
+ io.WriteString(w,"\r\n")
+ }
+ io.WriteString(w,"\r\n")
+ }
+
+ if current.Notes != nil && current.Notes.Plain.Content != "" {
+ io.WriteString(w,"> ")
+ io.WriteString(w,current.Notes.Plain.Content)
+ io.WriteString(w,"\r\n")
+ io.WriteString(w,"\r\n")
+ }
+ return nil
+ })
+}
--
2.29.2.windows.2
jan-bar commented
@mei-rune 我按照你的思路实现了可以自定义样式的方案,https://github.com/jan-bar/xmind/blob/master/example/save_markdown_test.go
你可以先试试看好不好用,有问题说下。在测试时还发现了一些优化项和bug,没问题的话我可以发布一个版本额。
mei-rune commented
暂时发现一个小 bug, Notes 可能是多行的, 所以加下列补丁就可以了
diff --git a/markdowm.go b/markdowm.go
index 94354cd..9c54398 100644
--- a/markdowm.go
+++ b/markdowm.go
@@ -9,11 +9,21 @@ import (
const (
DefaultMarkdownName = "default"
- DefaultMarkdownFormat = "{{Repeat \"#\" .Deep}} {{.Title}}\n\n{{range $i,$v := .Labels}}> {{$v}}\n\n{{end}}{{if .Notes}}> {{.Notes}}\n\n{{end}}"
+ DefaultMarkdownFormat = "{{Repeat \"#\" .Deep}} {{.Title}}\n\n{{range $i,$v := .Labels}}> {{$v}}\n\n{{end}}{{if .Notes}}{{range $i,$v := (SplitLines .Notes)}}> {{$v}}\n\n{{end}}\n\n{{end}}"
MarkdownKeyDeep = "Deep" // 所在层级,>=1
)
+func splitLines(s string) []string {
+ ss := strings.Split(s, "\n")
+ for idx := range ss {
+ if strings.HasSuffix(ss[idx], "\r") {
+ ss[idx] = strings.TrimSuffix(ss[idx], "\r")
+ }
+ }
+ return ss
+}
+
func (wk *WorkBook) SaveToMarkdown(w io.Writer, format map[string]string) error {
defText, ok := format[DefaultMarkdownName]
if !ok {
@@ -22,6 +32,7 @@ func (wk *WorkBook) SaveToMarkdown(w io.Writer, format map[string]string) error
tpl, err := template.New(DefaultMarkdownName).Funcs(template.FuncMap{
"Repeat": strings.Repeat, // 注册用到的方法
+ "SplitLines": splitLines,
}).Parse(defText)
if err != nil {
return err
mei-rune commented
转 markdown 的命令行小工具
package main
import (
"fmt"
"io/fs"
"os"
"path/filepath"
"strings"
"github.com/jan-bar/xmind"
)
func main() {
if len(os.Args) != 3 {
return
}
from := os.Args[1]
to := os.Args[2]
st, err := os.Stat(from)
if err != nil {
fmt.Println(err)
return
}
if st.IsDir() {
err = convertDir(from, to)
} else {
err = convertFile(from, to)
}
if err != nil {
fmt.Println(err)
return
}
}
func convertDir(from, to string) error {
return filepath.WalkDir(from, fs.WalkDirFunc(func(pa string, info fs.DirEntry, err error) error {
if info.IsDir() {
return nil
}
ext := filepath.Ext(pa)
if strings.ToLower(ext) != ".xmind" {
return nil
}
rel, err := filepath.Rel(from, pa)
if err != nil {
return err
}
targetDir := filepath.Join(to, filepath.Dir(rel))
if err = os.MkdirAll(targetDir, 0666); err != nil {
return err
}
return convertFile(pa, filepath.Join(targetDir, info.Name()+".md"))
}))
}
func convertFile(from, to string) error {
fmt.Println("convert", from)
book, err := xmind.LoadFile(from)
if err != nil {
return err
}
fw, err := os.Create(to)
if err != nil {
return err
}
//goland:noinspection GoUnhandledErrorResult
defer fw.Close()
err = book.SaveToMarkdown(fw, nil)
if err != nil {
return err
}
return nil
}