llamaindex 定义和自定义节点(Defining and Customizing Nodes)

定义和自定义节点(Defining and Customizing Nodes)

概念解释

节点(Nodes)表示源文档的“块”,无论是文本块、图像还是其他。它们还包含元数据和与其他节点及索引结构的关系信息。

节点是 LlamaIndex 中的一等公民。你可以选择直接定义节点及其所有属性,也可以选择通过我们的 NodeParser 类将源文档解析为节点。

使用模式
通过 NodeParser 解析节点

你可以使用 NodeParser 类将文档解析为节点。例如,使用 SentenceSplitter

from llama_index.core.node_parser import SentenceSplitter

parser = SentenceSplitter()

nodes = parser.get_nodes_from_documents(documents)
手动构造节点

你也可以选择手动构造节点对象并跳过第一个部分。例如:

from llama_index.core.schema import TextNode, NodeRelationship, RelatedNodeInfo

node1 = TextNode(text="<text_chunk>", id_="<node_id>")
node2 = TextNode(text="<text_chunk>", id_="<node_id>")

# 设置关系
node1.relationships[NodeRelationship.NEXT] = RelatedNodeInfo(
    node_id=node2.node_id
)
node2.relationships[NodeRelationship.PREVIOUS] = RelatedNodeInfo(
    node_id=node1.node_id
)

nodes 
<think> 我们正在处理Tiptap中自定义节点内容格式的还原问题。根据引用[2],Tiptap使用ProseMirror作为其底层引擎,因此我们需要利用ProseMirror的API来处理节点内容格式的还原。 还原自定义节点内容格式的核心在于: 1. 定义自定义节点的Schema(模式),包括节点名称、属性、内容模型等。 2. 在自定义节点的toDOM方法中,将节点数据转换为DOM结构(用于渲染)。 3. 在自定义节点的parseDOM方法中,定义如何从DOM结构解析回节点数据(用于还原)。 此外,引用[2]提到,ProseMirror使用整型的下标索引(pos)来定位文档中的位置,并且有强大的API来实现节点与位置之间的转换。但这里我们关注的是节点的序列化反序列化(即toDOMparseDOM)。 步骤: 1. 定义自定义节点,并在其中实现toDOMparseDOM方法。 2. 在toDOM方法中,将节点数据(包括属性内容)转换为DOM结构。 3. 在parseDOM方法中,定义匹配的DOM选择器,并编写从DOM元素提取节点数据的逻辑。 示例:假设我们有一个自定义节点“customNode”,它有一个属性“data-type”,并且内容为行内内容(inline content)。 代码示例: ```javascript import { Node } from '@tiptap/core' const CustomNode = Node.create({ name: 'customNode', group: 'block', content: 'inline*', // 允许行内内容 defining: true, // 对于块节点,确保在复制时保留 // 定义节点的属性 addAttributes() { return { 'data-type': { default: 'default-type' } } }, // 将节点渲染为DOM toDOM(node) { // 返回一个数组,第一个元素是标签名,第二个是属性对象,第三个是内容(0表示内容位置) return [ 'div', { 'data-type': node.attrs['data-type'], class: 'custom-node' }, 0 // 0表示子内容的位置 ] }, // 从DOM解析回节点 parseDOM: [{ // 匹配DOM的选择器 tag: 'div.custom-node', getAttrs(dom) { return { 'data-type': dom.getAttribute('data-type') } } }] }) ``` 这样,当编辑器加载内容时,遇到符合选择器`div.custom-node`的DOM元素,就会调用parseDOM方法,提取属性并创建自定义节点实例。同样,在输出内容时,通过toDOM方法将节点转换为DOM结构。 注意事项: 1. 如果自定义节点有复杂的内容结构,需要确保parseDOM能够正确解析子节点。在parseDOM中,子节点会自动根据内容模型(content)解析,所以我们只需要关注属性即可。 2. 如果自定义节点有多个可能的DOM表示,可以在parseDOM数组中添加多个匹配规则。 还原内容格式时,我们还需要确保自定义节点已经被添加到编辑器的extensions中。 另外,引用[1]提到Tiptap的内容转换功能在持续优化,所以建议关注官方文档以获取最新信息。 如果自定义节点包含嵌套结构,可能需要更复杂的解析规则,这时可以使用getContent方法来自定义内容的解析: ```javascript parseDOM: [{ tag: 'div.custom-node', getAttrs(dom) { return { 'data-type': dom.getAttribute('data-type') } }, getContent(dom, schema) { // 可以在这里手动解析子节点 // 但通常不需要,因为Tiptap会自动解析子节点,除非有特殊结构 // 默认情况下,内容会自动解析,所以这里一般不需要重写 } }] ``` 总结:还原自定义节点内容格式的关键在于正确实现节点的parseDOM方法,确保能够从DOM中提取出节点的属性内容。 相关问题: 1. 如何在Tiptap中注册自定义节点? 2. Tiptap中如何定义带有嵌套结构的自定义节点? 3. 如何测试Tiptap自定义节点的序列化反序列化? </think> 在 Tiptap 中还原自定义节点内容格式,关键在于正确实现节点的序列化(输出)反序列化(解析)逻辑。以下是具体实现方法: ### 核心实现步骤 1. **定义节点序列化(`toDOM`)方法** 将节点数据转换为 DOM 结构: ```javascript const CustomNode = Node.create({ toDOM(node) { return [ 'div', { 'data-type': node.attrs.type, // 保存自定义属性 class: 'custom-node' }, 0 // 0 表示子内容位置 ] } }) ``` 2. **实现节点解析(`parseDOM`)方法** 将 HTML 转换回节点数据: ```javascript parseDOM: [{ tag: 'div.custom-node', // 匹配的 DOM 选择器 getAttrs(dom) { return { type: dom.getAttribute('data-type'), // 还原属性 // 自动处理子内容 } } }] ``` 3. **完整节点定义示例** ```javascript import { Node } from '@tiptap/core' export default Node.create({ name: 'customNode', group: 'block', content: 'inline*', addAttributes() { return { type: { default: 'default' } } }, parseDOM: [{ tag: 'div.custom-node', getAttrs(dom) { return { type: dom.dataset.type || 'default' } } }], toDOM(node) { return ['div', { 'data-type': node.attrs.type, class: 'custom-node' }, ['span', { class: 'node-label' }, `类型: ${node.attrs.type}`], ['div', { class: 'content' }, 0] // 0 表示子内容插槽 ] } }) ``` ### 内容还原关键点 1. **属性映射** 使用 `dataset` 或 `getAttribute` 在 `parseDOM` 中还原自定义属性[^2]: ```javascript getAttrs(dom) { return { color: dom.style.color, level: parseInt(dom.dataset.level) } } ``` 2. **嵌套内容处理** 通过 `0` 占位符自动处理子内容: ```javascript toDOM() { return ['div', {}, 0] // 子内容将渲染在此位置 } ``` 3. **多格式支持** 添加多个解析规则处理不同 HTML 结构: ```javascript parseDOM: [ { tag: 'div.custom-node' }, // 新格式 { tag: 'span.legacy-node' } // 兼容旧格式 ] ``` 4. **内容转换 API** 使用 Tiptap 的内容转换器保持格式一致: ```javascript import { getHTML } from '@tiptap/html' // JSON 转 HTML const html = getHTML(docJson, [CustomNode]) // HTML 转 JSON const json = editor.storage.customNodeParser(html) ``` ### 验证与调试 1. **测试内容循环**: ```javascript // 验证序列化-解析循环 const node = editor.schema.nodes.customNode.create() const html = editor.view.dom.innerHTML editor.commands.setContent(html) // 应保持相同结构 ``` 2. **查看解析结果**: ```javascript console.log(editor.getJSON()) // 检查还原的节点数据 ``` 当处理复杂节点时,可能需要使用 `ProseMirror` 的 `DOMParser` 进行低级操作[^2]: ```javascript import { DOMParser } from 'prosemirror-model' const parser = DOMParser.fromSchema(editor.schema) const doc = parser.parse(divElement) // 手动解析DOM ``` > 提示:Tiptap的内容转换功能持续优化,建议定期关注[官方更新日志](https://tiptap.dev/releases)获取最新API改进[^1]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

需要重新演唱

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值