实现 SiYuan 笔记图、表和公式的自动编号和交叉引用

本贴最后更新于 555 天前,其中的信息可能已经时异事殊

对图、表和公式的自动编号和交叉引用是科研笔记最基本的功能,但当前各种笔记系统均未实现该功能。因此,抽出一天时间,利用 Quicker 并结合 C#代码,针对 Siyuan 做了一下尝试。虽然还有待完善,但也基本实现了该功能,见图 11

交叉引用 - 动作信息 - Quicker (getquicker.net)

主要功能:

  1. 实现对图进行自动编号,同时增减图刷新后,编号将进行全自动更新;

  2. 实现对表进行自动编号,同时增减表刷新后,编号将进行全自动更新;

  3. 实现对公式进行自动编号,同时增减公式刷新后,编号将进行全自动更新;

  4. 实现了对图表和公式的交叉引用,同时增删图表和公式后将自动更新交叉引用

image

图 1 界面

主要代码如下:

using Newtonsoft.Json; using Newtonsoft.Json.Linq; using System.Net.Http; using System.Text; using System.Threading.Tasks; using System.Collections.Generic; using System.Linq; using System.Text.RegularExpressions; public static string Exec(string paramValue) { JObject Jobj=JObject.Parse(paramValue); string block_id = (string)Jobj["block_id"]; string API_token= (string)Jobj["API_token"]; string cmd = (string)Jobj["cmd"]; string data = (string)Jobj["data"]; if (cmd.ToLower()=="setcaption"){ SetCaption(data, block_id,API_token); } else if (cmd.ToLower()=="clear"){ ClearCaptionInfo(block_id,API_token); } else if (cmd.ToLower()=="update") { UpdateCaptions(block_id,API_token); } return ""; } private static Dictionary<string, string> ial2JSON(string ial, string mk) { Dictionary<string, string> mydict = new Dictionary<string, string>(); foreach (Match m in Regex.Matches(ial, "([\\w-]+)=\"([^\"]*)\"")) { mydict.Add(m.Groups[1].Value, m.Groups[2].Value); } mydict.Add("mk", mk); return mydict; } public static string ClearCaptionInfo(string block_id, string Token) { SYAPI siyuanAPI = new SYAPI(Token); JObject myJobj = new JObject(); myJobj["custom-type"] = ""; myJobj["custom-id"] = ""; myJobj["name"] = ""; siyuanAPI.SetBlockAttrs(block_id, myJobj); siyuanAPI.PushMsg("已完成更新!"); return ""; } public static string SetCaption(string CaptionLabel, string block_id, string Token) { SYAPI siyuanAPI = new SYAPI(Token); JObject result=siyuanAPI.SQL_query(string.Format("Select markdown from blocks where id='{0}'", block_id)); string cmk = (string)result["data"][0]["markdown"]; Dictionary<string, string> cdict = new Dictionary<string, string>() { { "custom-type",CaptionLabel}, { "custom-id","1"}, { "name",CaptionLabel+" 1"}, { "id",block_id}, { "mk",cmk} }; string doc_id = siyuanAPI.GetDocumentIDbyBlockID(block_id); result = siyuanAPI.SQL_query(string.Format("select markdown,ial from blocks where id in (SELECT block_id FROM attributes where name='custom-type' and root_id='{0}') ", doc_id)); List<Dictionary<string, string>> data = result["data"].Select(x => ial2JSON((string)x["ial"], (string)x["markdown"])).ToList<Dictionary<string, string>>(); data.Add(cdict); result = siyuanAPI.GetChildBlocks(doc_id); List<string> idx = result["data"].Select(x => (string)x["id"]).ToList<string>(); data = data.OrderBy(mdict => idx.IndexOf(mdict["id"])).ToList(); Dictionary<string, int> CaptionDictID = new Dictionary<string, int>(); foreach (Dictionary<string, string> item in data) { string captionLabel = item["custom-type"]; int seqID = int.Parse(item["custom-id"]); string id = item["id"]; string name = item["name"]; string mk = item["mk"]; if (CaptionDictID.Keys.Contains(captionLabel)) { CaptionDictID[captionLabel] += 1; } else { CaptionDictID[captionLabel] = 1; } if ((new string[] { "式", "equation", "eq", "eq.", "公式" }).Contains(captionLabel.ToLower())) { mk = Regex.Replace(mk, "^\\$\\$", ""); mk = Regex.Replace(mk, "\\$\\$$", ""); mk = Regex.Replace(mk.Trim(), @"\\tag ?\{ ?(\d+-)?\d+ ?\}", ""); name = captionLabel + " " + CaptionDictID[captionLabel].ToString(); siyuanAPI.UpdateBlock(id, string.Format("$${0}\\tag{{{1}{2}}}$$", mk.Trim(), "", CaptionDictID[captionLabel])); } else { string pattern = string.Format("^(?<header>[#\\* ]*)(?<CaptionLabel>{0} \\d{{1,3}})?(?<last>.*)$", captionLabel); GroupCollection groups = Regex.Match(mk, pattern).Groups; mk = groups["header"].ToString().Trim() + captionLabel + " " + CaptionDictID[captionLabel].ToString() + " " + groups["last"].ToString().Trim(); siyuanAPI.UpdateBlock(id, mk); } JObject myJobj = new JObject(); myJobj["custom-type"] = captionLabel; myJobj["custom-id"] = CaptionDictID[captionLabel].ToString(); myJobj["name"] = captionLabel + " " + CaptionDictID[captionLabel].ToString(); siyuanAPI.SetBlockAttrs(id, myJobj); } return ""; } public static void UpdateCaptions(string block_id, string Token) { SYAPI siyuanAPI = new SYAPI(Token); string doc_id = siyuanAPI.GetDocumentIDbyBlockID(block_id); JObject result = siyuanAPI.SQL_query(string.Format("select markdown,ial from blocks where id in (SELECT block_id FROM attributes where name='custom-type' and root_id='{0}') ", doc_id)); List<Dictionary<string, string>> data = result["data"].Select(x => ial2JSON((string)x["ial"], (string)x["markdown"])).ToList<Dictionary<string, string>>(); result = siyuanAPI.GetChildBlocks(doc_id); List<string> idx = result["data"].Select(x => (string)x["id"]).ToList<string>(); data = data.OrderBy(mdict => idx.IndexOf(mdict["id"])).ToList(); Dictionary<string, int> CaptionDictID = new Dictionary<string, int>(); foreach (Dictionary<string, string> item in data) { string captionLabel = item["custom-type"]; int seqID = int.Parse(item["custom-id"]); string id = item["id"]; string name = item["name"]; string mk = item["mk"]; if (CaptionDictID.Keys.Contains(captionLabel)) { CaptionDictID[captionLabel] += 1; } else { CaptionDictID[captionLabel] = 1; } if ((new string[] { "式", "equation", "eq", "eq.", "公式" }).Contains(captionLabel.ToLower())) { mk = Regex.Replace(mk, "^\\$\\$", ""); mk = Regex.Replace(mk, "\\$\\$$", ""); mk = Regex.Replace(mk.Trim(), @"\\tag ?\{ ?(\d+-)?\d+ ?\}", ""); name = captionLabel + " " + CaptionDictID[captionLabel].ToString(); siyuanAPI.UpdateBlock(id, string.Format("$${0}\\tag{{{1}{2}}}$$", mk.Trim(), "", CaptionDictID[captionLabel])); } else { string pattern = string.Format("^(?<header>[#\\* ]*)(?<CaptionLabel>{0} \\d{{1,3}})?(?<last>.*)$", captionLabel); GroupCollection groups = Regex.Match(mk, pattern).Groups; mk = groups["header"].ToString().Trim() + captionLabel + " " + CaptionDictID[captionLabel].ToString() + " " + groups["last"].ToString().Trim(); siyuanAPI.UpdateBlock(id, mk); } JObject myJobj = new JObject(); myJobj["custom-type"] = captionLabel; myJobj["custom-id"] = CaptionDictID[captionLabel].ToString(); myJobj["name"] = captionLabel + " " + CaptionDictID[captionLabel].ToString(); siyuanAPI.SetBlockAttrs(id, myJobj); } siyuanAPI.PushMsg("已完成更新!"); } public class SYAPI { private string _TokenID; public SYAPI(string TokenID) { _TokenID = TokenID; } private async Task<JObject> CommandAsync(string path, JObject data) { string url = "http://127.0.0.1:6806"; url = url + path; var body = new StringContent(JsonConvert.SerializeObject(data), Encoding.UTF8, "application/json"); using (HttpClient client = new HttpClient()) { client.DefaultRequestHeaders.Add("Authorization", "Token " + _TokenID); HttpResponseMessage response = await client.PostAsync(url, body); response.EnsureSuccessStatusCode(); string responseBody = await response.Content.ReadAsStringAsync(); return (JObject.Parse(responseBody)); } } public JObject lsNotebooksAsync() { return (CommandAsync("/api/notebook/lsNotebooks", new JObject()).Result); } public JObject PushMsg(string msg) { return CommandAsync("/api/notification/pushMsg", JObject.FromObject(new { msg = msg, timeout = 7000 })).Result; } public JObject PushErrMsg(string msg) { return CommandAsync("/api/notification/pushMsg", JObject.FromObject(new { msg = msg, timeout = 7000 })).Result; } public JObject SQL_query(string SQL) { return CommandAsync("/api/query/sql", JObject.FromObject(new { stmt = SQL, })).Result; } #region Block块 public JObject UpdateBlock(string block_id, string markdown, string dataType = "markdown") { return CommandAsync("/api/block/updateBlock", JObject.FromObject(new { id = block_id, dataType = dataType, data = markdown })).Result; } public JObject GetBlockInfo(string block_id) { return CommandAsync("/api/block/getBlockInfo", JObject.FromObject(new { id = block_id, })).Result; } public JObject GetBlockKramdown(string block_id) { return CommandAsync("/api/block/getBlockKramdown", JObject.FromObject(new { id = block_id, })).Result; } public JObject GetChildBlocks(string block_id) { return CommandAsync("/api/block/getChildBlocks", JObject.FromObject(new { id = block_id })).Result; } public JObject SetBlockAttrs(string block_id, object dict) { return CommandAsync("/api/attr/setBlockAttrs", JObject.FromObject(new { id = block_id, attrs = JObject.FromObject(dict), })).Result; } public JObject ResetBlockAttrs(string block_id, object dict) { return CommandAsync("/api/attr/resetBlockAttrs", JObject.FromObject(new { id = block_id, attrs = JObject.FromObject(dict), })).Result; } #endregion #region Document public string GetDocumentIDbyBlockID(string block_id) { JObject result = SQL_query(string.Format(" select root_id from blocks where id='{0}'", block_id)); return (string)result["data"][0]["root_id"]; } #endregion }


  1. 图 1 界面

  • 公式
    5 引用 • 24 回帖
  • 思源笔记

    思源笔记是一款隐私优先的个人知识管理系统,支持完全离线使用,同时也支持端到端加密同步。

    融合块、大纲和双向链接,重构你的思维。

    23531 引用 • 95399 回帖
  • C#
    29 引用 • 34 回帖 • 5 关注
  • Quicker

    Quicker 您的指尖工具箱!操作更少,收获更多!

    34 引用 • 150 回帖 • 3 关注
1 操作
ttChen 在 2023-07-08 20:51:27 更新了该帖

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...
  • ttChen

    @88250 最近在开发一款 Siyuan 的文献管理插件。已知 Siyuan 可以通过 setBlockAttrs API 函数修改块的属性,通过·updateBlock API 函数更新块的内容,都是基于块的,请问有没有一种 API 函数能更新行内元素的内容和属性?这对开发文献管理插件非常有帮助。

    image.png

    1 回复
  • 其他回帖
  • updateBlockdataType 参数改成 markdown 了吗?

    1 回复
  • 只能把加背景的这几个字改成加粗,比如:

    { "id": "20230712190919-obqieuq", "dataType": "markdown", "data": "foo ((20230712211410-ktc4oa8 'bar')) baz **bazz**{: style=\"background-color: var(--b3-font-background1);\"}^[1]^\n{: updated=\"20230712211420\" id=\"20230712190919-obqieuq\"}" }
    1 回复
  • 是的,做不到仅修改部分行级元素,用 kramdown 只能整块更新。

    1 回复
  • 查看全部回帖

推荐标签 标签

  • 代码片段

    代码片段分为 CSS 与 JS 两种代码,添加在 [设置 - 外观 - 代码片段] 中,这些代码会在思源笔记加载时自动执行,用于改善笔记的样式或功能。

    用户在该标签下分享代码片段时需在帖子标题前添加 [css] [js] 用于区分代码片段类型。

    102 引用 • 715 回帖
  • golang

    Go 语言是 Google 推出的一种全新的编程语言,可以在不损失应用程序性能的情况下降低代码的复杂性。谷歌首席软件工程师罗布派克(Rob Pike)说:我们之所以开发 Go,是因为过去 10 多年间软件开发的难度令人沮丧。Go 是谷歌 2009 发布的第二款编程语言。

    497 引用 • 1388 回帖 • 275 关注
  • OkHttp

    OkHttp 是一款 HTTP & HTTP/2 客户端库,专为 Android 和 Java 应用打造。

    16 引用 • 6 回帖 • 76 关注
  • ActiveMQ

    ActiveMQ 是 Apache 旗下的一款开源消息总线系统,它完整实现了 JMS 规范,是一个企业级的消息中间件。

    19 引用 • 13 回帖 • 669 关注
  • Facebook

    Facebook 是一个联系朋友的社交工具。大家可以通过它和朋友、同事、同学以及周围的人保持互动交流,分享无限上传的图片,发布链接和视频,更可以增进对朋友的了解。

    4 引用 • 15 回帖 • 437 关注
  • BookxNote

    BookxNote 是一款全新的电子书学习工具,助力您的学习与思考,让您的大脑更高效的记忆。

    笔记整理交给我,一心只读圣贤书。

    1 引用 • 1 回帖 • 1 关注
  • MyBatis

    MyBatis 本是 Apache 软件基金会 的一个开源项目 iBatis,2010 年这个项目由 Apache 软件基金会迁移到了 google code,并且改名为 MyBatis ,2013 年 11 月再次迁移到了 GitHub。

    170 引用 • 414 回帖 • 379 关注
  • Netty

    Netty 是一个基于 NIO 的客户端-服务器编程框架,使用 Netty 可以让你快速、简单地开发出一个可维护、高性能的网络应用,例如实现了某种协议的客户、服务端应用。

    49 引用 • 33 回帖 • 20 关注
  • AWS
    11 引用 • 28 回帖 • 1 关注
  • 自由行
    6 关注
  • wolai

    我来 wolai:不仅仅是未来的云端笔记!

    2 引用 • 14 回帖 • 1 关注
  • Spring

    Spring 是一个开源框架,是于 2003 年兴起的一个轻量级的 Java 开发框架,由 Rod Johnson 在其著作《Expert One-On-One J2EE Development and Design》中阐述的部分理念和原型衍生而来。它是为了解决企业应用开发的复杂性而创建的。框架的主要优势之一就是其分层架构,分层架构允许使用者选择使用哪一个组件,同时为 JavaEE 应用程序开发提供集成的框架。

    943 引用 • 1460 回帖 • 3 关注
  • 京东

    京东是中国最大的自营式电商企业,2015 年第一季度在中国自营式 B2C 电商市场的占有率为 56.3%。2014 年 5 月,京东在美国纳斯达克证券交易所正式挂牌上市(股票代码:JD),是中国第一个成功赴美上市的大型综合型电商平台,与腾讯、百度等中国互联网巨头共同跻身全球前十大互联网公司排行榜。

    14 引用 • 102 回帖 • 345 关注
  • 国际化

    i18n(其来源是英文单词 internationalization 的首末字符 i 和 n,18 为中间的字符数)是“国际化”的简称。对程序来说,国际化是指在不修改代码的情况下,能根据不同语言及地区显示相应的界面。

    8 引用 • 26 回帖 • 2 关注
  • Bug

    Bug 本意是指臭虫、缺陷、损坏、犯贫、窃听器、小虫等。现在人们把在程序中一些缺陷或问题统称为 bug(漏洞)。

    76 引用 • 1741 回帖 • 1 关注
  • 支付宝

    支付宝是全球领先的独立第三方支付平台,致力于为广大用户提供安全快速的电子支付/网上支付/安全支付/手机支付体验,及转账收款/水电煤缴费/信用卡还款/AA 收款等生活服务应用。

    29 引用 • 347 回帖 • 1 关注
  • 旅游

    希望你我能在旅途中找到人生的下一站。

    93 引用 • 899 回帖 • 1 关注
  • 一些有用的避坑指南。

    69 引用 • 93 回帖 • 1 关注
  • ZooKeeper

    ZooKeeper 是一个分布式的,开放源码的分布式应用程序协调服务,是 Google 的 Chubby 一个开源的实现,是 Hadoop 和 HBase 的重要组件。它是一个为分布式应用提供一致性服务的软件,提供的功能包括:配置维护、域名服务、分布式同步、组服务等。

    59 引用 • 29 回帖 • 9 关注
  • Excel
    30 引用 • 28 回帖
  • C

    C 语言是一门通用计算机编程语言,应用广泛。C 语言的设计目标是提供一种能以简易的方式编译、处理低级存储器、产生少量的机器码以及不需要任何运行环境支持便能运行的编程语言。

    85 引用 • 165 回帖 • 4 关注
  • 开源中国

    开源中国是目前中国最大的开源技术社区。传播开源的理念,推广开源项目,为 IT 开发者提供了一个发现、使用、并交流开源技术的平台。目前开源中国社区已收录超过两万款开源软件。

    7 引用 • 86 回帖
  • H2

    H2 是一个开源的嵌入式数据库引擎,采用 Java 语言编写,不受平台的限制,同时 H2 提供了一个十分方便的 web 控制台用于操作和管理数据库内容。H2 还提供兼容模式,可以兼容一些主流的数据库,因此采用 H2 作为开发期的数据库非常方便。

    11 引用 • 54 回帖 • 656 关注
  • Access
    1 引用 • 3 回帖 • 1 关注
  • 数据库

    据说 99% 的性能瓶颈都在数据库。

    344 引用 • 723 回帖
  • TextBundle

    TextBundle 文件格式旨在应用程序之间交换 Markdown 或 Fountain 之类的纯文本文件时,提供更无缝的用户体验。

    1 引用 • 2 回帖 • 56 关注
  • OneDrive
    2 引用