xml - 在现有文档的特定位置插入 XML 节点

标签 xml xslt insert xsd

我有一个包含一些可选节点的现有 XML 文档,我想插入一个新节点,但在某个位置。

文档看起来像这样:

<root>
  <a>...</a>
  ...
  <r>...</r>
  <t>...</t>
  ...
  <z>...</z>
</root>

新节点 ( <s>...</s> ) 应插入节点 <r> 之间和 <t> ,导致:

<root>
  <a>...</a>
  ...
  <r>...</r>
  <s>new node</s>
  <t>...</t>
  ...
  <z>...</z>
</root>

问题是现有节点是可选的。因此,我无法使用 XPath 查找节点 <r>并在其后插入新节点。

我想避免“暴力法”:从 <r> 搜索最多 <a>找到一个存在的节点。

我还想保留顺序,因为 XML 文档必须符合 XML 架构。

可以使用 XSLT 以及普通的 XML 库,但由于我只使用 Saxon-B,所以模式感知 XSLT 处理不是一个选项。

有没有人知道如何插入这样的节点?

谢谢,MyKey_

最佳答案

[替换了我的上一个答案。现在我更明白你需要什么了。]

这是一个 XSLT 2.0 解决方案:

<xsl:stylesheet version="2.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

  <xsl:template match="/root">
    <xsl:variable name="elements-after" select="t|u|v|w|x|y|z"/>
    <xsl:copy>
      <xsl:copy-of select="* except $elements-after"/>
      <s>new node</s>
      <xsl:copy-of select="$elements-after"/>
    </xsl:copy>
  </xsl:template>

</xsl:stylesheet>

您必须明确列出后面的元素或前面的元素。 (您不必同时列出两者。)我倾向于选择两个列表中较短的一个(因此在上面的示例中使用“t”-“z”,而不是“a”-“r”)。

可选增强:

这样就完成了工作,但现在您需要在两个不同的地方(在 XSLT 和模式中)维护元素名称列表。如果变化很大,那么它们可能会不同步。如果您将新元素添加到模式但忘记将其添加到 XSLT,则它不会被复制。如果您担心这一点,您可以实现自己的模式感知。假设您的架构如下所示:

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">

  <xs:element name="root">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="a" type="xs:string"/>
        <xs:element name="r" type="xs:string"/>
        <xs:element name="s" type="xs:string"/>
        <xs:element name="t" type="xs:string"/>
        <xs:element name="z" type="xs:string"/>
      </xs:sequence>
    </xs:complexType>
  </xs:element>

</xs:schema>

现在您需要做的就是更改 $elements-after 变量的定义:

  <xsl:variable name="elements-after" as="element()*">
    <xsl:variable name="root-decl" select="document('root.xsd')/*/xs:element[@name eq 'root']"/>
    <xsl:variable name="child-decls" select="$root-decl/xs:complexType/xs:sequence/xs:element"/>
    <xsl:variable name="decls-after" select="$child-decls[preceding-sibling::xs:element[@name eq 's']]"/>
    <xsl:sequence select="*[local-name() = $decls-after/@name]"/>
  </xsl:variable>

这显然更复杂,但现在您不必在代码中列出任何元素(“s”除外)。每当您更改模式(特别是如果您要添加新元素)时,脚本的行为都会自动更新。这是否矫枉过正取决于您的项目。我只是将它作为一个可选的附加组件提供。 :-)

关于xml - 在现有文档的特定位置插入 XML 节点,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/862954/

相关文章:

PHP 特殊字符解析错误

java - 如何使用 Java 提取 XML 节点中的值列表

php - 重复 key 更新时 - 增加 2

android - 在Android中动态填充微调器?

xml - xslt中的时区转换

regex - 如何将文件的内容插入到 perl/shell 中的另一个文件(如果正则表达式)中

xml - NodeJS xpath 库是否支持 XPath 查询表达式?

xml - 如何在 Linux 中查找和替换多行文本?

ant - 如何让 xslt 缩进 xml(来自 Ant)?

xml - XSLT 替换属性值和文本节点中的文本