You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

使用Saxon与XSLT 3.0实现指定XML节点按序插入合并的方案与样式表示例

Saxon与XSLT 3.0实现指定XML节点按序插入合并的方案与样式表示例

嘿,我帮你梳理了这个XML节点合并的需求,用XSLT 3.0配合Saxon就能完美解决,下面是完整的方案、代码和细节说明:

先明确咱们的核心需求

  • merge.xml里的每个<mergeinto>/<mergecontent>节点,按顺序对应插入到merge-test.xml的每个<entry>节点中
  • 插入位置固定在<title><content type='html'>之间
  • 两个文件的节点数量完全匹配,直接按位置对应即可,不需要排序
  • 最终输出结构保持merge-test.xml的Atom feed格式,保存为output.xml

补全完整的merge.xml示例(你之前的输入不完整,我帮你补全了)

<?xml version='1.0' encoding='utf-8'?>
<feed xmlns='http://www.w3.org/2005/Atom' xmlns:blogger='http://schemas.google.com/blogger/2018'>
  <mergeinto>
    <mergecontent>Lorem Ipsum Content 1</mergecontent>
  </mergeinto>
  <mergeinto>
    <mergecontent>Lorem Ipsum Content 2</mergecontent>
  </mergeinto>
  <mergeinto>
    <mergecontent>Lorem Ipsum Content 3</mergecontent>
  </mergeinto>
  <mergeinto>
    <mergecontent>Lorem Ipsum Content 4</mergecontent>
  </mergeinto>
</feed>

完整的XSLT 3.0样式表merge-stylesheet.xsl

我写了两种插入逻辑的实现,你可以根据需求选一种:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="3.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xpath-default-namespace="http://www.w3.org/2005/Atom"
  xmlns:blogger="http://schemas.google.com/blogger/2018"
  exclude-result-prefixes="#all">

  <!-- 提前加载外部merge.xml的所有合并内容 -->
  <xsl:variable name="merge-content-list" select="document('merge.xml')/*/mergeinto/mergecontent" />

  <!-- 身份模板:默认复制所有节点和属性,保持原文档结构 -->
  <xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>

  <!-- 方案一:按节点整体顺序插入(适合entry内节点顺序固定的场景) -->
  <xsl:template match="entry">
    <xsl:copy>
      <!-- 先复制entry里除content外的所有节点 -->
      <xsl:apply-templates select="@*|node()[not(self::content)]"/>
      <!-- 插入当前entry对应的mergecontent -->
      <mergecontent>
        <xsl:value-of select="$merge-content-list[position() = current()/position()]"/>
      </mergecontent>
      <!-- 最后复制原有的content节点 -->
      <xsl:apply-templates select="content"/>
    </xsl:copy>
  </xsl:template>

  <!-- 方案二:精准在title之后插入(推荐!即使entry内其他节点顺序变化也不影响位置) -->
  <!-- 如果你需要更精准的插入位置,注释掉上面的entry模板,打开下面这两个模板 -->
  <!--
  <xsl:template match="entry">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()">
        <!-- 用隧道参数传递当前entry对应的merge内容 -->
        <xsl:with-param name="target-merge-content" select="$merge-content-list[position() = current()/position()]" tunnel="yes"/>
      </xsl:apply-templates>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="title">
    <xsl:param name="target-merge-content" tunnel="yes"/>
    <!-- 先复制原有的title节点 -->
    <xsl:copy-of select="."/>
    <!-- 立刻插入mergecontent -->
    <mergecontent>
      <xsl:value-of select="$target-merge-content"/>
    </mergecontent>
  </xsl:template>
  -->

</xsl:stylesheet>

关键细节拆解(帮你避坑)

  1. 命名空间处理:用xpath-default-namespace指定默认的Atom命名空间,避免每次写元素都要加前缀,解决XML命名空间匹配的常见坑
  2. 位置对应逻辑$merge-content-list[position() = current()/position()] 让每个entry严格对应同位置的mergecontent节点,完美匹配你的顺序需求
  3. 两种方案的区别
    • 方案一写法简单,适合entry内节点顺序固定的场景
    • 方案二用隧道参数精准控制插入位置,即使entry里的其他节点顺序变动,mergecontent也会牢牢插在title后面

用Saxon运行的命令行

确保你已经下载了Saxon的JAR包(比如saxon-he-12.4.jar),打开命令行执行:

java -jar saxon-he-12.4.jar -s:merge-test.xml -xsl:merge-stylesheet.xsl -o:output.xml

最终输出的output.xml片段示例

每个entry里都会在title和content之间出现对应的mergecontent:

<entry>
  <id>tag:blogger.com,1999:blog-17477.post-670855911</id>
  <blogger:type>POST</blogger:type>
  <blogger:status>LIVE</blogger:status>
  <author>
    <name>Author</name>
    <uri>Author Link</uri>
    <blogger:type>BLOGGER</blogger:type>
  </author>
  <title>Title Title</title>
  <mergecontent>Lorem Ipsum Content 1</mergecontent>
  <content type='html'>Content Content Content Content Content</content>
  <!-- 其他原有节点保持不变 -->
</entry>

如果需要调整mergecontent的命名空间、标签名,或者修改插入位置,直接改样式表的对应部分就行,非常灵活~

火山引擎 最新活动