guide文档导入和导出

# 概述

文档导入/导出功能允许用户导出和导入整个文档,包括

  • 活动的协作编辑会话或存储内容(如果不存在活动的协作会话且已启用文档存储),
  • 评论,
  • 建议,
  • 修订历史。

# 文档导入/导出与协作导入/导出

有一个类似的 协作导入和导出 功能,允许导入和导出服务器上的数据。这两个功能的主要区别在于,文档导入/导出允许将文档视为一个包含内容、建议、评论等信息的单个资源。这种方法的主要优点是减少了从服务器初始化和导出所有文档数据所需的请求数量。第二个区别是,协作导入和导出 功能仅在活动的协作会话上运行,这意味着不会导出文档存储中的数据。此外,文档导出功能允许获取文档内容,而无需建议/评论标记。

例如,文档导出/导入工作流程可能如下所示

  1. 通过连接 CKEditor 5 导入文档数据或创建新的协作编辑会话。
  2. 协作编辑文档 - 添加和修改内容、评论和建议。
  3. 导出文档数据 - 将导出的文档数据保存到客户端的存储中。
  4. 删除文档数据。

您可能会注意到,从 协作导入和导出 功能导出的内容包含评论/建议标记。请记住,那里只有 CKEditor 标记。评论或建议标记需要服务器数据库中存在实际的评论或建议对象。这意味着,如果您从 协作导入和导出 功能导出内容,然后永久删除数据库中的评论和建议,则使用 协作导入和导出 功能的下次文档导入将导致文档损坏。因此,对于这种情况,请改用此 文档导入和导出 功能。

# 导出前提条件

  • 需要上传 编辑器捆绑包
  • 导出的文档需要存在于活动的协作编辑会话或文档存储中。

# 导出使用

导出整个文档意味着返回活动的协作编辑会话或文档存储(如果存在)中的数据,以及所有与文档相关的数据,如评论和建议。这是通过向我们 REST APIGET /documents/{document_id} 发送请求来完成的。
您还可以使用此功能快速导出内容,而无需包含建议或评论标记,无需修改原始文档。

# 导入前提条件

  • 需要上传 编辑器捆绑包
  • 目标文档既不应该存在于协作会话中,也不应该存在于文档存储中。
  • 相关的评论和建议不应该存在于数据库中。

# 导入使用

导入整个文档意味着使用请求主体中的文档数据创建新的协作编辑会话,包括协作编辑会话数据、评论和建议。这是通过向 REST APIPOST /documents 发送请求来完成的。

# 示例

以下示例是在 Node.js 中准备的。

  1. 运行以下命令
mkdir cs-import-export-example && cd cs-import-export-example && npm init -y && npm i axios && touch importExport.cjs
  1. 打开 cs-import-export-example/importExport.cjs 并粘贴以下代码片段
const crypto = require( 'crypto' );
const axios = require( 'axios' );

// Update with your credentials and application endpoint
const environmentId = 'txQ9sTfqmXUyWU5LmDbr';
const apiSecret = '4zZBCQoPfRZ7Rr7TEnGAuRsGgbfF58Eg0PA8xcLD2kvPhjGjy4VGgB8k0hXn';
const applicationEndpoint = 'https://33333.cke-cs.com';

// Set document id
const documentId = 'my_document_id';

const importApiEndpoint = `${ applicationEndpoint }/api/v5/${ environmentId }/documents`;
const exportApiEndpoint = `${ applicationEndpoint }/api/v5/${ environmentId }/documents/${ documentId }`;

const importBody = {
    id: documentId,
    content: {
        bundle_version: '34.1.0',
        data: '<h2><comment-start name=\"e712d8a9d63d6f1201576ccb7c0f15a77:cd907\"></comment-start>Hello world<comment-end name=\"e712d8a9d63d6f1201576ccb7c0f15a77:cd907\"></comment-end> from <suggestion-start name=\"insertion:ed7c304a37913421ddc1d7950a144d41d:user-1\"></suggestion-start>example suggestion <suggestion-end name=\"insertion:ed7c304a37913421ddc1d7950a144d41d:user-1\"></suggestion-end>CKEditor 5!</h2>'
    },
    comments: [
        {
            id: 'e52d6b88056950a3d98ecd4f10053a74c',
            document_id: documentId,
            thread_id: 'e712d8a9d63d6f1201576ccb7c0f15a77',
            content: '<p>example comment</p>',
            attributes: {},
            updated_at: '2022-09-28T18:11:47.258Z',
            created_at: '2022-09-28T18:11:47.239Z',
            user: {
                id: 'user-1'
            },
            type: 1
        }
    ],
    suggestions: [
        {
            id: 'ed7c304a37913421ddc1d7950a144d41d',
            document_id: documentId,
            has_comments: false,
            attributes: {},
            created_at: '2022-09-28T18:11:23.726Z',
            author_id: 'user-1',
            state: 'open',
            type: 'insertion',
            requester_id: 'user-1'
        }
    ]
};

( async () => {
    await importDocument( importBody );

    const exportedData = await exportDocument();

    console.log( 'Exported data:' );
    console.log( exportedData );

    async function importDocument( body ) {
        try {
            const config = getConfig( 'POST', importApiEndpoint, body );
            const response = await axios.post( importApiEndpoint, body, config );

            console.log( response.status );

            return response.data;
        } catch ( error ) {
            console.log( error.message );
            console.log( error.response.data );
        }
    }

    async function exportDocument() {
        try {
            const config = getConfig( 'GET', exportApiEndpoint );
            const response = await axios.get( exportApiEndpoint, config );

            return response.data;
        } catch ( error ) {
            console.log( error.message );
            console.log( error.response.data );
        }
    }
} )();

function getConfig( method, url, body ) {
    const CSTimestamp = Date.now();

    return {
        headers: {
            'X-CS-Timestamp': CSTimestamp,
            'X-CS-Signature': generateSignature( apiSecret, method, url, CSTimestamp, body )
        }
    };
}

function generateSignature( secret, method, uri, timestamp, body ) {
    const url = new URL( uri );
    const path = url.pathname + url.search;
    const hmac = crypto.createHmac( 'SHA256', secret );

    hmac.update( `${ method.toUpperCase() }${ path }${ timestamp }` );

    if ( body ) {
        hmac.update( Buffer.from( JSON.stringify( body ) ) );
    }

    return hmac.digest( 'hex' );
}
  1. 更新代码片段中的凭据和 documentId 值。

  2. 执行 node importExport.cjs 命令。

在导入请求成功响应状态代码 201 后,您可以使用与代码片段中设置的相同的 documentId 打开编辑器,以查看导入的内容。此外,导出的文档内容应打印在控制台上。

# 故障排除

  • 如果在导入过程中任何操作失败,例如导入评论失败,则将撤销导入文档的所有数据。
  • 我们建议启用 洞察面板,您将在其中找到整个过程的详细日志,包括任何失败请求的确切原因。

# 更多信息

您可以在我们的 REST API 文档 中找到更多信息。