How to edit specific xml using xpath

后端 未结 1 901
北恋
北恋 2021-01-24 19:31

I have got below xml which is genrated using xslt function json-to-xml(). I need to update this xml as shown in Result xml using given xpaths. I need the solution in java or xs

相关标签:
1条回答
  • 2021-01-24 20:21

    One approach given XSLT 3 might be to transform those paths you have into XSLT 3 match templates and then create a stylesheet you can execute with the transform function (https://www.w3.org/TR/xpath-functions/#func-transform):

    <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        xmlns:xs="http://www.w3.org/2001/XMLSchema"
        xmlns:axsl="http://www.w3.org/1999/XSL/Transform-alias"
        exclude-result-prefixes="xs"
        version="3.0">
    
        <xsl:namespace-alias stylesheet-prefix="axsl" result-prefix="xsl"/>
    
        <xsl:output method="xml" indent="yes"/>
    
        <xsl:param name="paths" as="xs:string">/Response/Payload/root/cars[2]/strength=999
            /Response/Payload/root/bikes[1]/model=2019
            /Response/Headers/server=WebSphere
            /Response/Headers/Content-Type=text
            /Response/Payload/root/cars[2]/Capacity=555
            /Response/Payload/root/cars[1]/model=mmm1
            /Response/Payload/root/bikes[1]/company=xyz
            /Response/Payload/root/cars[1]/company=ccc1
            /Response/Headers/Status-Code=400</xsl:param>
    
        <xsl:param name="path-sequence" as="xs:string*" select="tokenize($paths, '\s+')!normalize-space()"/>
    
        <xsl:variable name="stylesheet">
            <axsl:stylesheet version="3.0">
                <axsl:mode on-no-match="shallow-copy"/>
    
                <xsl:for-each select="($path-sequence)">
                    <xsl:variable name="steps" select="tokenize(., '/')"/>
                    <axsl:template>
                        <xsl:attribute name="match">
                            <xsl:apply-templates select="tail($steps)" mode="step"/>
                        </xsl:attribute>
                        <axsl:copy>
                            <axsl:copy-of select="@*"/>
                            <xsl:value-of select="substring-after($steps[last()], '=')"/>
                        </axsl:copy>                   
                    </axsl:template>
                </xsl:for-each>
    
            </axsl:stylesheet>
        </xsl:variable>
    
        <xsl:template match=".[not(contains(., '[')) and not(contains(., '='))]" mode="step">
            <xsl:if test="position() gt 1">/</xsl:if>
            <xsl:sequence select="'*[@key = ''' || . || ''']'"/>
        </xsl:template>
    
        <xsl:template match=".[contains(., '=')]" mode="step">
            <xsl:if test="position() gt 1">/</xsl:if>
            <xsl:sequence select="'*[@key = ''' || substring-before(., '=') || ''']'"/>
        </xsl:template>
    
        <xsl:template match=".[contains(., '[')]" mode="step">
            <xsl:if test="position() gt 1">/</xsl:if>
            <xsl:sequence select="'*[@key = ''' || substring-before(., '[') || ''']/*[' || replace(., '^[^\[]+\[([0-9]+)\]', '$1') || ']'"/>
        </xsl:template>
    
        <xsl:template match="/">
            <xsl:sequence select="transform(map {
                'source-node' : .,
                'stylesheet-node' : $stylesheet
              })?output"/>
        </xsl:template>
    
    </xsl:stylesheet> 
    

    At https://xsltfiddle.liberty-development.net/jyyiVhv/1 I get the wanted result

    <?xml version="1.0" encoding="UTF-8"?>
    <map xmlns="http://www.w3.org/2005/xpath-functions">
        <map key="Response">
            <map key="Headers">
                <string key="server">WebSphere</string>
                <string key="Status-Code">400</string>
                <string key="Content-Type">text</string>
            </map>
            <map key="Payload">
                <map key="root">
                    <array key="cars">
                        <map>
                            <string key="company">ccc1</string>
                            <string key="model">mmm1</string>
                        </map>
                        <map>
                            <string key="strength">999</string>
                            <string key="Capacity">555</string>
                        </map>
                    </array>
                    <array key="bikes">
                        <map>
                            <string key="company">xyz</string>
                            <string key="model">2019</string>
                        </map>
                    </array>
                </map>
            </map>
        </map>
    </map>
    

    that way although I had to adapt the paths including bikes to bikes[1].

    0 讨论(0)
提交回复
热议问题