我有下面的降价
## Hello
### This is a test message
Ligisnfmkdfn
Run Code Online (Sandbox Code Playgroud)
我使用 GO 模块gomarkdown通过 CommonExtensions 和 AutoHeadingIDs 解析器将 markdown 转换为 HTML,我得到的结果是
<h2 id="helo">Hello</h2>
<h3 id="this-is-a-test-message">This is a test message</h3>
<p>Ligisnfmkdfn</p>
Run Code Online (Sandbox Code Playgroud)
我怎样才能得到像在nodejs中使用markdown-it-header-sections一样的结果
<section id="helo">
<h2>Hello</h2>
<section id="this-is-a-test-message">
<h3>This is a test message</h3>
<p>Ligisnfmkdfn</p>
</section>
</section>
Run Code Online (Sandbox Code Playgroud)
这是一个相当完整的解决方案:
\npackage main\n\nimport (\n "fmt"\n "io"\n "regexp"\n "strings"\n\n "github.com/gomarkdown/markdown"\n "github.com/gomarkdown/markdown/ast"\n "github.com/gomarkdown/markdown/html"\n)\n\n// levels tracks how deep we are in a heading "structure"\nvar levels []int\n\nfunc hasLevels() bool {\n return len(levels) > 0\n}\n\nfunc lastLevel() int {\n if hasLevels() {\n return levels[len(levels)-1]\n }\n return 0\n}\n\nfunc popLevel() int {\n level := lastLevel()\n levels = levels[:len(levels)-1]\n return level\n}\n\nfunc pushLevel(x int) {\n levels = append(levels, x)\n}\n\nvar reID = regexp.MustCompile(`\\s+`)\n\n// renderSections catches an ast.Heading node, and wraps the node\n// and its "children" nodes in <section>...</section> tags; there\'s no\n// real hierarchy in Markdown, so we make one up by saying things like:\n// - H2 is a child of H1, and so forth from 1 \xe2\x86\x92 2 \xe2\x86\x92 3 ... \xe2\x86\x92 N\n// - an H1 is a sibling of another H1\nfunc renderSections(w io.Writer, node ast.Node, entering bool) (ast.WalkStatus, bool) {\n openSection := func(level int, id string) {\n w.Write([]byte(fmt.Sprintf("<section id=\\"%s\\">\\n", id)))\n pushLevel(level)\n }\n closeSection := func() {\n w.Write([]byte("</section>\\n"))\n popLevel()\n }\n\n if _, ok := node.(*ast.Heading); ok {\n level := node.(*ast.Heading).Level\n if entering {\n // close heading-sections deeper than this level; we\'ve "come up" some number of levels\n for lastLevel() > level {\n closeSection()\n }\n\n txtNode := node.GetChildren()[0]\n if _, ok := txtNode.(*ast.Text); !ok {\n panic(fmt.Errorf("expected txtNode to be *ast.Text; got %T", txtNode))\n }\n headTxt := string(txtNode.AsLeaf().Literal)\n id := strings.ToLower(reID.ReplaceAllString(headTxt, "-"))\n\n openSection(level, id)\n }\n }\n\n // at end of document\n if _, ok := node.(*ast.Document); ok {\n if !entering {\n for hasLevels() {\n closeSection()\n }\n }\n }\n\n // continue as normal\n return ast.GoToNext, false\n}\n\nfunc main() {\n lines := []string{\n "## Hello",\n "### This is a test message",\n "Ligisnfmkdfn",\n }\n md := strings.Join(lines, "\\n")\n\n opts := html.RendererOptions{\n Flags: html.CommonFlags,\n RenderNodeHook: renderSections,\n }\n renderer := html.NewRenderer(opts)\n\n html := markdown.ToHTML([]byte(md), nil, renderer)\n\n fmt.Println(string(html))\n}\nRun Code Online (Sandbox Code Playgroud)\n当我运行它时,我得到:
\n<section id="hello">\n <h2>Hello</h2>\n <section id="this-is-a-test-message">\n <h3>This is a test message</h3>\n <p>Ligisnfmkdfn</p>\n </section>\n</section>\nRun Code Online (Sandbox Code Playgroud)\n我说它还算完整,因为它足够聪明,可以处理如下输入:
\nlines := []string{\n "# H1\xce\xb1",\n "## H2A",\n "## H2B",\n "## H2C",\n "### H31",\n "#### H4I",\n "## H2D",\n "# H1\xce\xb2",\n "## H2E",\n}\nRun Code Online (Sandbox Code Playgroud)\n它产生:
\n<section id="h1\xce\xb1">\n <h1>H1\xce\xb1</h1>\n <section id="h2a">\n <h2>H2A</h2>\n </section>\n <section id="h2b">\n <h2>H2B</h2>\n </section>\n <section id="h2c">\n <h2>H2C</h2>\n <section id="h31">\n <h3>H31</h3>\n <section id="h4i">\n <h4>H4I</h4>\n </section>\n </section>\n </section>\n <section id="h2d">\n <h2>H2D</h2>\n </section>\n</section>\n<section id="h1\xce\xb2">\n <h1>H1\xce\xb2</h1>\n <section id="h2e">\n <h2>H2E</h2>\n </section>\n</section>\nRun Code Online (Sandbox Code Playgroud)\n但我还没有对此进行严格测试,所以我不确定它可能在哪里不符合预期。
\n