首页 > 解决方案 > 如果 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),我可以设置该值。

任何关于如何解决这个问题的意见都非常感谢。

标签: xmloffice-js

解决方案


是的。欢迎来到 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, "&amp;") + '</' + 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.")
        }
      });
    });
  });
}

推荐阅读