主要内容

本页采用了机器翻译。点击此处可查看英文原文。

使用命令行 API 更新或修复需求链接

此示例涵盖了当一个或多个工件被移动或重命名后,设计工件和需求之间的链接变得过时的一组标准情况。我们不想删除断开的链接并创建新的链接,而是想更新现有的链接,以便保留创建/修改历史和其他属性(描述、关键字、注释等)。

示例工程文件

开始之前,请运行 slreq.clear 命令以确保系统处于干净的初始状态。然后打开 CruiseRequirementsExample 工程。这会将链接的工件文件集合解压到 MATLAB/Projects 文件夹下的新子文件夹中。

slreq.clear
openProject("CruiseRequirementsExample");

Simulink 模型与需求相关

我们将重点关注该工程依赖关系图的一小部分:打开 crs_plant.slx Simulink® 模型,该模型有多个指向外部 Microsoft® Word 文档 crs_reqs.docx 的链接。

open_system("crs_plant");

The project dependency graph shows how the files relate to each other

导航其中一个链接来打开链接的文档。

rmi("view","crs_plant/status",1);

The Simulink model shows the navigation to the System outputs requirement

Word 文档打开到相应部分:

The Word document is on section 4.2, system outputs

以下是如何使用命令行 API 并检查从 crs_plant.slxcrs_reqs.docx 的链接。

linkSet = slreq.find("type","LinkSet","Name","crs_plant");
links = linkSet.getLinks;
disp("Original Links to Word document:");
Original Links to Word document:
for i = 1:numel(links)
    linkTarget = links(i).getReferenceInfo;
    if contains(linkTarget.artifact,"crs_req.docx")
        source = links(i).source;
disp(["    found link from " strrep(getfullname( ...
[bdroot source.id]),newline,"") ...
" to crs_req.docx"]);
    end
end

在存在导入引用的情况下导航直接链接

通过在 MATLAB® 命令行中输入 slreq.editor 打开需求编辑器。您将看到已加载两个需求集:crs_req.slreqxcrs_req_func_spec.slreqx。第一组需求是由从 crs_req.docx, 导入的引用集合,第二组则是通过需求编辑器手动创建的。如果您现在关闭 Word 文档并从 crs_plant/status Inport 模块导航相同的链接,则相应的导入的引用将在需求编辑器中突出显示,因为导航操作在已加载的导入需求集中找到了匹配的引用。

The Requirements Editor shows two requirements

您仍然可以使用在文档中显示按钮在原始文档的上下文中查看链接的需求。

slreq.editor;
rmidotnet.MSWord.application("kill");
rmi("view","crs_plant/status",1);

用例 1:文档重命名后批量更新链接

假设收到了需求文档的更新版本,名为 crs_req_v2.docx。我们现在希望 crs_plant.slx 中的链接指向更新文档的相应部分。为了本例的目的,我们将在同一文件夹中复制原始文档并修改其名称。然后,我们使用 slreq.LinkSet API 批量更新给定 LinkSet 中的所有链接,以连接到文档的较新副本:

copyfile(fullfile(pwd,"documents","crs_req.docx"),...
    fullfile(pwd,"documents","crs_req_v2.docx"));
linkSet.updateDocUri("crs_req.docx","crs_req_v2.docx");

验证匹配链接的更新

现在我们可以浏览相同的链接并确认打开了外部文档的适当版本。如果我们像前面一样迭代所有链接,这可以确认所有 4 个链接均按预期更新:

rmi("view","crs_plant/status",1); % updated document opens
links = linkSet.getLinks;
disp("Links to Word document after update:");
Links to Word document after update:
for i = 1:numel(links)
    source = links(i).source;
    linkTarget = links(i).getReferenceInfo;
    if contains(linkTarget.artifact,"crs_req.docx")
        warning(["link from " source.id ...
            " still points to crs_req.docx"]);  % should not happen
    elseif contains(linkTarget.artifact,"crs_req_v2.docx")
disp(["    found link from " strrep(getfullname( ...
[bdroot source.id]),newline," ")...
" to crs_req_v2.docx"]);
    end
end

更新链接后导航至导入的参考文献

如上所示,当需求编辑器中提供了导入的引用时,导航链接将选择匹配的引用对象。但是,我们刚刚更新了文档 crs_req_v2.docx 新版本的链接,并且没有该文档的导入引用。在需求编辑器下从 Simulink 模块导航可将您直接带到外部 Word 文档。

The Word document is on section 4.2, system outputs

为了避免这种不一致,我们需要更新先前导入的参考文献以便与更新的文档名称关联。我们使用slreq.ReqSet API 来完成这项任务。此外,由于更新后的文档可能修改了需求,我们必须使用 updateFromDocument API 来提取存储在 Requirements Toolbox 端的引用项的更新。完成后,从 Simulink 模型导航将找到匹配的导入引用。

The Requirements Editor shows two requirement sets and the system outputs requirement is selected

查找具有导入引用资料的需求集。更新源文件位置并找到顶级导入节点。

reqSet = slreq.find("type","ReqSet","Name","crs_req");
reqSet.updateSrcFileLocation("crs_req.docx","crs_req_v2.docx"); 
importNode = reqSet.find("CustomId","crs_req_v2");

从源文件更新导入的引用。关闭 Microsoft Word。然后,导航到需求编辑器中更新的引用。

importNode.updateFromDocument;
rmidotnet.MSWord.application("kill");
rmi("view","crs_plant/status",1);

用例 1 后的清理

放弃链接数据更改以避免工程关闭时出现提示。关闭工程(也清理 MATLAB 路径更改)。关闭 Microsoft Word。

slreq.clear;                        
close(currentProject);
rmidotnet.MSWord.application("kill"); 

用例 2:批量更新链接以完全依赖导入的引用

如上面的用例 1 所示,当文档被移动或重命名时,需要付出额外的努力来维护与外部文档的“直接链接”。更好的工作流程是将现有的“直接链接”转换为“引用链接”,这些链接指向 *``.slreqx 文件中导入的 References,并且不再重复有关原始文档位置或名称的信息。使用此选项时,外部源文档关联仅存储在承载导入引用的需求集中。

为了演示此工作流程,请通过在新的子文件夹中重新打开 CruiseRequirementsExample 工程从同一初始点重新启动。将 Simulink 模型复制到您的目录并打开它。

openProject("CruiseRequirementsExample");
copyfile(fullfile(pwd,"documents/crs_req.docx"),...
    fullfile(pwd,"documents/crs_req_v2.docx"));
open_system("crs_plant");

使用导入的引用资料查找 crs_plant 链接集和 crs_req 需求集。

linkSet = slreq.find("type","LinkSet","Name","crs_plant");
reqSet = slreq.find("type","ReqSet","Name","crs_req");

然后我们使用 slreq.LinkSet API 来更新 crs_plant.slmx 中的所有直接链接。然后创建链接集中所有链接的数组。

linkSet.redirectLinksToImportedReqs(reqSet);
links = linkSet.getLinks;

以此方式更新 LinkSet 后,循环遍历所有链接以确认不存在指向 crs_req.docx 文件的“直接”链接。

disp("Check for links to original external document:");
Check for links to original external document:
counter = 0;
for i = 1:numel(links)
    linkTarget = links(i).getReferenceInfo;
    if contains(linkTarget.artifact,"crs_req.docx")
        source = links(i).source;
        warning(["link from " source.id " still points to crs_req.docx"]);
        counter = counter + 1;
    end
end
disp(["    Total " num2str(counter) " links to external document"]);
    "    Total "    "0"    " links to external document"

从 Simulink 模型导航到更新的引用。

rmi("view","crs_plant/status",1);

参考文献链接和外部文档重命名

现在,当所有链接指向导入的参考文献而不是外部文档时,只要导入节点针对新的外部文档名称进行了更新,可追溯性数据在文档重命名后仍保持一致。与用例 1 一样,我们将假装存在外部需求文档的更新版本,通过使用新名称重新保存我们的 Word 文档。然后,我们使用与之前相同的 API 对导入节点执行所需的更新。现在,由于链接依赖于导入的引用,并且不存储有关导入文档的信息,从 Simulink 模型导航将带我们到更新的引用,与执行用例 1 的所有步骤后相同。

The Requirements Editor shows two requirement sets and the system outputs requirement is selected

该引用现在与更新的外部文档相关联,[在文档中显示] 按钮打开更新的(重命名的)文档,并且不需要在 LinkSet 端进行进一步调整。

查找具有导入引用资料的需求集。更新源文件位置并找到顶级导入节点。

reqSet = slreq.find("type","ReqSet","Name","crs_req");
reqSet.updateSrcFileLocation("crs_req.docx","crs_req_v2.docx"); 
importNode = reqSet.find("CustomId","crs_req_v2");

从源文件更新导入的引用。然后,导航到需求编辑器中更新的引用。

importNode.updateFromDocument;
rmi("view","crs_plant/status","1");

用例 2 后的清理

放弃链接数据更改以避免工程关闭时出现提示。关闭工程(也清理 MATLAB 路径更改)。关闭 Microsoft Word。

slreq.clear;                        
close(currentProject);
rmidotnet.MSWord.application("kill"); 

用例 3:将链接的工件移动到新工程

现在假设我们正在对一个具有链接工件的现有工程进行分支,并且我们需要创建一组新的重命名工件,其中包含与原始工程相同的所有可追溯性链接。与之前一样,我们将 CruiseRequirementsExample 工程提取到一个新的子文件夹中,并将“直接链接”转换为“引用链接”,就像我们在上面的用例 2 中所做的那样。然后,我们通过将每个关联的工件重新保存为以 _********************v2 为后缀的名称,来创建这些工件的“新版本”。

在创建 Simulink 模型、导入的外部文档和包含导入需求的需求集的重命名副本后,出现一个问题:重命名的模型链接到原始需求集中的引用,而不是重命名的需求集中的引用。在详细信息窗格中的链接下,链接显示为未解析,因为未加载原始模型。

The Requirements Editor has the System outputs requirement selected. The right pane has the Properties and Links sections are expanded

打开 CruiseRequirementsExample 工程并打开 crs_plant 模型。找到 crs_plant 的链接集和需求集 crs_req

openProject("CruiseRequirementsExample");
open_system("models/crs_plant.slx");
linkSet = slreq.find("type","LinkSet","Name","crs_plant");
reqSet = slreq.find("type","ReqSet","Name","crs_req");

将直接链接转换为引用链接。创建文件的重命名副本并保存。

linkSet.redirectLinksToImportedReqs(reqSet);     
mkdir(fullfile(pwd,"copied"));
Warning: Directory already exists.
save_system("crs_plant",fullfile(pwd,"copied","crs_plant_v2.slx"));  
reqSet.save(fullfile(pwd,"copied","crs_req_v2.slreqx"));              
copyfile(fullfile("documents","crs_req.docx"),fullfile("copied","crs_req_v2.docx"));

将重命名的需求集与重命名的文档关联。找到顶级导入节点。

reqSet.updateSrcFileLocation("crs_req.docx",fullfile(pwd,...
    "copied","crs_req_v2.docx"));
importNode = reqSet.find("CustomId","crs_req_v2");

通过更新导入的参考文献,确保重命名的需求集中的内容与重命名的文档的内容相匹配。从重命名的 Simulink 模型导航到重命名的需求集中的项。原始需求集中的旧项被突出显示,这是不正确的。

updateFromDocument(importNode);
rmi("view","crs_plant_v2/status",1);

更新重命名源中的链接以使用重命名的目标作为目标

与用例 1 类似,我们可以使用 LinkSet.updateDocUri(OLD,NEW) API 来更新 crs_plant_v2.slmx 中的链接,以使用重命名的需求集 crs_req_v2.slreqx 作为链接目标,而不是原来的 crs_req.slreqx。完成后,从重命名的模型中的模块再次导航。选定重命名的需求集中的需求,并解析右下角链接下的详细信息窗格中的链接。

The Requirements Editor has the system outputs requirement selected. The Properties and Links sections are expanded and the links are resolved

找到模型新副本 crs_plant_v2 的链接集。更新与模型新副本相链接的需求集的名称。从重命名的 Simulink 模型导航到重命名的需求集中的项。这一次,它突出显示了正确的项。

linkSet = slreq.find("type","LinkSet","Name","crs_plant_v2");
linkSet.updateDocUri("crs_req.slreqx","crs_req_v2.slreqx");
rmi("view","crs_plant_v2/status",1);