xml - 如果 xml 节点为空,则在 Word 加载项中的自定义 xml 属性上设置文本值失败
问题描述
我正在尝试在 Word 加载项(桌面)中为自定义 xml 属性设置文本值。自定义属性又在 SharePoint 中定义,并对应于 SharePoint 中的字段/内容类型。
我遇到的问题是,仅当节点已经设置了值时,设置文本值才有效。如果它是空的office.js
,将返回一个错误code: 6100
和 message 'Custom XML Error.'
。
给定以下自定义 xml:
<?xml version="1.0" encoding="utf-8"?>
<p:properties xmlns:p="http://schemas.microsoft.com/office/2006/metadata/properties"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:pc="http://schemas.microsoft.com/office/infopath/2007/PartnerControls">
<documentManagement>
<foo xmlns="757d984d-6dab-4bc2-83cc-8319df82947b" xsi:nil="true"/>
<bar xmlns="757d984d-6dab-4bc2-83cc-8319df82947b">Bar text value</bar>
</documentManagement>
</p:properties>
并给出示例片段:
function setTextExample (theNode, value) {
const XML_NS = 'http://schemas.microsoft.com/office/2006/metadata/properties'
Office.context.document.customXmlParts.getByNamespaceAsync(XML_NS, (result) => {
if (result.status !== Office.AsyncResultStatus.Succeeded) return
const part = result.value[0]
part.getNodesAsync('*/documentManagement/*', (result) => {
if (result.status !== Office.AsyncResultStatus.Succeeded) return
result.value.forEach(node => {
if (node.baseName === theNode) {
node.setTextAsync(value, (result) => {
if (result.status === Office.AsyncResultStatus.Succeeded) {
console.log('OK, it worked')
} else {
console.error('failed to set node text', result.error)
}
})
}
})
})
})
}
setTextExample('foo', 'foo value') // <foo> has no text value, always results in code 6100.
setTextExample('bar', 'bar value') // <bar> has a text value, works fine.
我相信这在某种程度上与<foo>
具有xsi:nil="true"
属性集的节点有关,因为如果我删除它(通过手动解压缩文件、编辑自定义 xml 文件并将文件压缩回 .docx),我可以设置该值。
任何关于如何解决这个问题的意见都非常感谢。
解决方案
是的。欢迎来到 OfficeJS 和微软文档不足的痛苦世界。
你对这xsi:nil
部分的怀疑是正确的。我有同样的拔毛经历。
微妙的原因是,当您使用该setTextAsync
方法时,生成的 XML 将是:
更新前:
<foo xmlns="757d984d-6dab-4bc2-83cc-8319df82947b" xsi:nil="true"/>
更新后:
<foo xmlns="757d984d-6dab-4bc2-83cc-8319df82947b" xsi:nil="true">foo value</foo>
所以,NIL 属性仍然存在,但它现在也有一个文本值,因此 XML 6100 错误。
因此,您需要使用setXmlAsync
方法 - 这是丑陋的,但唯一的出路。Word API 1.1 缺乏为我们处理 SharePoint 属性提供更具保护性的环境。Word Preview API 已经有一年多没有交付了,令人沮丧的是,它提供了一个更清洁的 API - 所以看到它只是在我们的伤口上撒盐。
相反,我不得不在我的代码中设置 NIL 值。它只是一个非常糟糕的 API。
完整代码块:
export async function setDocumentProperty(name, value) {
backstage("SET START: SharePoint Property: " + name + "=" + value);
return Word.run(async context => {
Office.context.document.customXmlParts.getByNamespaceAsync(settings.namespace, function(result) {
var xpart = result.value[0];
var xpath = `//*[local-name() = '${name}']`;
xpart.getNodesAsync(xpath, function(nodeResults) {
var found = nodeResults.value.length
if (found) {
var node = nodeResults.value[0];
var xml = '<' + name + ' xmlns="' + node.namespaceUri +'"';
if (value) {
xml += '>' + value.replace(/&/g, "&") + '</' + name + '>'; // the value is tangible
} else {
// xml += ' xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true" />"; // otherwise handle blank values
xml += ' xsi:nil="true"/>'; // otherwise handle blank values
}
// node.setXmlAsync(xml, { asyncContext: "StateNormal" }, function(setResult) {
// node.setTextAsync(value, { asyncContext: "StateNormal" }, function(setResult) {
// node.setNodeValueAsync(value, { asyncContext: "StateNormal" }, function(setResult) {
backstage_xml(xml);
node.setXmlAsync(xml, { asyncContext: "StateNormal" }, function(setResult) {
if (setResult.status == Office.AsyncResultStatus.Failed) {
backstage_error("SET END: SharePoint Property - " + name + " FAILED with: " + setResult.error.code + SPACE + setResult.error.message);
} else {
backstage("SET END: SharePoint Property - " + name + "=" + value + ". Status=" + setResult.status);
}
});
} else {
backstage_error("SET END: SharePoint Property - " + name + " node not found.")
}
});
});
});
}
推荐阅读
- node.js - 来自变量 LdapJS 中的 LDAP 查询的数据
- python - Python:直接从 Pandas 加载 Oracle 表(写入 Oracle)
- sql-server - SQL - 将几个日期记录转换为单个日期范围
- java - 如果我只想检查进程是否正常启动,是否应该读取输出/错误流
- azure - 无法安装 VSTS 代理 Azure VM 扩展
- python - 子进程内的python子进程
- unity3d - Unity 未在事件字段中显示公共方法
- java - Junit 配置错误:您必须为此 @ParameterizedTest 提供至少一个参数
- django - gunicorn:在描述的情况下,有没有更好的方法来重新加载 gunicorn?
- xmlunit-2 - XMLUnit - 重复元素名称的不同元素选择器