You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用XSLT基于指定XPath修改特定XML结构

XSLT Solution to Modify XML with Custom XPath-like Rules

Problem Context

This is a follow-up to your earlier Stack Overflow question about editing specific XML with XPath, but the current XML uses the http://www.w3.org/2005/xpath-functions namespace and a nested map/string/array structure—so the previous solution needs adjustments to work with this setup.

Original XML

<?xml version="1.0" encoding="UTF-8"?>
<map xmlns="http://www.w3.org/2005/xpath-functions">
    <map key="Request">
        <map key="Headers">
            <string key="Accept">application/json</string>
            <string key="Content-Type">application/json</string>
        </map>
        <map key="Payload">
            <map key="root">
                <array key="req1">
                    <string>puneet</string>
                    <string>taneja</string>
                </array>
                <array key="req2">
                    <string>ratan</string>
                </array>
            </map>
        </map>
    </map>
</map>

Custom XPath-like Rules

These are your target update rules (note: these aren't standard XPath, so we'll parse them in the XSLT):

/Request/Headers/Accept=app
/Request/Headers/Content-Type=json
/Request/Payload/root/req1[2]=singh
/Request/Payload/root/req1[1]=pradeep
/Request/Payload/root/req2=suman

Desired Updated XML

<?xml version="1.0" encoding="UTF-8"?>
<map xmlns="http://www.w3.org/2005/xpath-functions">
    <map key="Request">
        <map key="Headers">
            <string key="Accept">application/json</string>
            <string key="Content-Type">application/json</string>
        </map>
        <map key="Payload">
            <map key="root">
                <array key="req1">
                    <string>pradeep</string>
                    <string>singh</string>
                </array>
                <array key="req2">
                    <string>suman</string>
                </array>
            </map>
        </map>
    </map>
</map>

Adapted XSLT Solution

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:fn="http://www.w3.org/2005/xpath-functions"
    exclude-result-prefixes="fn">

    <!-- Parameter to hold your update rules -->
    <xsl:param name="update-rules">
        <rule>/Request/Headers/Accept=app</rule>
        <rule>/Request/Headers/Content-Type=json</rule>
        <rule>/Request/Payload/root/req1[2]=singh</rule>
        <rule>/Request/Payload/root/req1[1]=pradeep</rule>
        <rule>/Request/Payload/root/req2=suman</rule>
    </xsl:param>

    <!-- Identity template: copy all nodes by default -->
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

    <!-- Template to update string nodes inside arrays or maps -->
    <xsl:template match="fn:string">
        <!-- Generate the path of the current node to match your rule format -->
        <xsl:variable name="current-path">
            <xsl:for-each select="ancestor-or-self::*[starts-with(local-name(), 'map') or starts-with(local-name(), 'array')]">
                <xsl:if test="position() > 1">/</xsl:if>
                <xsl:value-of select="@key"/>
                <!-- Add index if parent is an array -->
                <xsl:if test="parent::fn:array">
                    <xsl:text>[</xsl:text>
                    <xsl:value-of select="position()"/>
                    <xsl:text>]</xsl:text>
                </xsl:if>
            </xsl:for-each>
            <!-- Append string key if directly under a map -->
            <xsl:if test="parent::fn:map">
                <xsl:value-of select="concat('/', @key)"/>
            </xsl:if>
        </xsl:variable>

        <!-- Find matching rule for this path -->
        <xsl:variable name="matching-rule" select="$update-rules/rule[starts-with(., concat('/', $current-path, '='))]"/>
        
        <xsl:copy>
            <xsl:apply-templates select="@*"/>
            <!-- Use new value if rule exists, else keep original -->
            <xsl:choose>
                <xsl:when test="$matching-rule">
                    <xsl:value-of select="substring-after($matching-rule, '=')"/>
                </xsl:when>
                <xsl:otherwise>
                    <xsl:value-of select="."/>
                </xsl:otherwise>
            </xsl:choose>
        </xsl:copy>
    </xsl:template>

    <!-- Special case: handle rules targeting single-element arrays directly -->
    <xsl:template match="fn:array[string]">
        <xsl:variable name="array-key" select="@key"/>
        <xsl:variable name="parent-path">
            <xsl:for-each select="ancestor::fn:map">
                <xsl:if test="position() > 1">/</xsl:if>
                <xsl:value-of select="@key"/>
            </xsl:for-each>
        </xsl:variable>
        <xsl:variable name="rule-path" select="concat('/', $parent-path, '/', $array-key)"/>
        <xsl:variable name="matching-rule" select="$update-rules/rule[starts-with(., concat($rule-path, '='))]"/>

        <xsl:copy>
            <xsl:apply-templates select="@*"/>
            <xsl:choose>
                <xsl:when test="$matching-rule">
                    <string>
                        <xsl:value-of select="substring-after($matching-rule, '=')"/>
                    </string>
                </xsl:when>
                <xsl:otherwise>
                    <xsl:apply-templates select="node()"/>
                </xsl:otherwise>
            </xsl:choose>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

Key Adjustments Explained

  1. Namespace Handling: We declare the fn prefix for the http://www.w3.org/2005/xpath-functions namespace to correctly target nodes in the XML.
  2. Rule Parsing: The XSLT accepts your custom path=value rules as a parameter, then generates matching paths for each node to check against the rules.
  3. Array Index Support: For elements inside array nodes, we generate paths with positional indices (like req1[1]) to align with your rule format.
  4. Single-Element Array Fix: We handle rules that target an array directly (e.g., /Request/Payload/root/req2=suman) by updating its single child string node.

内容的提问来源于stack exchange,提问作者VSS

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 10:10:37