开发者

Update text in an element - Effectively

开发者 https://www.devze.com 2023-02-20 11:12 出处:网络
I need help from experts here to optimize the solution of updating string value in an element . I have this xml file as an input...

I need help from experts here to optimize the solution of updating string value in an element . I have this xml file as an input...

<?xml version="1.0" encoding="UTF-8"?>
<FullRequest>
    <Header>
        <Looptimes>3</Looptimes>
        <SomeElement>blah!</SomeElement>
        <AnotherElement>blah!!</AnotherElement>
    </Header>
    <RequestDetail>
        <!-- Request Element is a string of fixed length (50 characters) -->
        <Request>THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG AGAIN!</Request>
        <Request>THE TIME FOX JUMPED OVER THE LAZY DOG, PROGRESSED!</Request>
        <Request>OWING TO THE WIDESPREAD KNOWLEDGE OF THE PHRASE AN</Request>
    </RequestDetail>
</FullRequest>

Offset 5 in Request element will be unique and can be cross-referenced. Q, T and G are the IDs in the above request.

<?xml version="1.0" encoding="UTF-8"?>
<FullResponse>
    <Header>
        <Looptimes>3</Looptimes>
        <SomeElement>blah!</SomeElement>
        <AnotherElement>blah!!</AnotherElement>
    </Header>
    <ResponseDetail>
        <!-- Response element repeats for 3 times as indicated by the value of Looptimes -->
        <!-- Id has a unique value -->
        <Response>
            <Id>Q</Id>
            <Value1>ABC</Value1>
            <Value2>XYZ</Value2>
            <Value3>FGK&开发者_Go百科lt;/Value3>
        </Response>
        <Response>
            <Id>T</Id>
            <Value1>123</Value1>
            <Value2>YOK</Value2>
            <Value3>DSL</Value3>
        </Response>
        <Response>
            <Id>G</Id>
            <Value1>BAT</Value1>
            <Value2>TKR</Value2>
            <Value3>LAF</Value3>
        </Response>
    </ResponseDetail>
</FullResponse>

Taking the above xml, offset positions 10, 15 and 20 need to be replaced with values Value1, Value2 and Value3 respectively.

I have this XSL which does the job. Not sure how good this solution will work with few thousand records of 5000 characters each (50 characters in the Request element shown as an example here) with about 20 locations to edit.

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:regexp="http://exslt.org/regular-expressions" exclude-result-prefixes="regexp">
    <xsl:output omit-xml-declaration="no" indent="yes"/>
    <xsl:preserve-space elements="*"/>

    <xsl:variable name="WebResponse" select="document('local:///ic1-data.xml')"/>
    <xsl:template match="node() | @*">
        <xsl:copy>
            <xsl:apply-templates select="node() | @*"/>
        </xsl:copy>

    </xsl:template>

    <xsl:template match="/FullRequest/RequestDetail/Request">
        <xsl:variable name="currentLine" select="."/>
        <xsl:variable name="id" select="substring($currentLine,5,1)"/>
        <xsl:for-each select="$WebResponse/FullResponse/ResponseDetail/Response">
            <xsl:variable name="ResId" select="Id"/>

            <xsl:if test="$id = $ResId">
                <xsl:element name="{name()}">
                    <!-- Update Value1 -->
                    <xsl:variable name="from" select="substring($currentLine,10,3)"/>
                    <xsl:variable name="UpdatedValue1"
                        select="regexp:replace($currentLine,$from,'',Value1)"/>

                    <!-- Update Value2 -->
                    <xsl:variable name="from2" select="substring($UpdatedValue1,15,3)"/>
                    <xsl:variable name="UpdatedValue2"
                        select="regexp:replace($UpdatedValue1,$from2,'',Value2)"/>

                    <!-- Update Value3 -->
                    <xsl:variable name="from3" select="substring($UpdatedValue2,20,3)"/>
                    <xsl:value-of select="regexp:replace($UpdatedValue2,$from3,'',Value3)"/>
                </xsl:element>
            </xsl:if>
        </xsl:for-each>
    </xsl:template>
</xsl:stylesheet>

The sample output will be as:

<?xml version="1.0" encoding="UTF-8"?>
<FullRequest>
    <Header>
        <Looptimes>3</Looptimes>
        <SomeElement>blah!</SomeElement>
        <AnotherElement>blah!!</AnotherElement>
    </Header>
    <RequestDetail>
        <Response>THE QUICKABCOWXYZOXFGKMPS OVER THE LAZY DOG AGAIN!</Response>
        <Response>THE TIME 123 JYOKEDDSLER THE LAZY DOG, PROGRESSED!</Response>
        <Response>OWING TO BAT WTKRSPLAFD KNOWLEDGE OF THE PHRASE AN</Response>
    </RequestDetail>
</FullRequest>

I can only use XSLT 1.0

Can you suggest how to make this better?

Thanks.


Another more flexible approach would be:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:strip-space elements="*"/>
    <xsl:key name="kResponseById" match="Response" use="Id"/>
    <xsl:variable name="WebResponse" select="document('ic1-data.xml')"/>
    <xsl:template match="node()|@*">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="Request/text()">
        <xsl:variable name="vCurrent" select="."/>
        <xsl:for-each select="$WebResponse">
            <xsl:call-template name="replace">
                <xsl:with-param name="pString" select="$vCurrent"/>
                <xsl:with-param name="pValues"
                     select="key('kResponseById',
                                 substring($vCurrent,5,1)
                             )/*[starts-with(local-name(),'Value')]"/>
            </xsl:call-template>
        </xsl:for-each>
    </xsl:template>
    <xsl:template name="replace">
        <xsl:param name="pString"/>
        <xsl:param name="pValues"/>
        <xsl:choose>
            <xsl:when test="$pValues">
                <xsl:variable name="pLimit"
                    select="substring-after(
                               local-name($pValues[1]),
                               'Value'
                            ) * 5 + 4"/>
                <xsl:call-template name="replace">
                    <xsl:with-param name="pString"
                         select="concat(
                                    substring($pString, 1, $pLimit),
                                    $pValues[1],
                                    substring($pString, $pLimit + 4)
                                 )"/>
                    <xsl:with-param name="pValues"
                         select="$pValues[position()!=1]"/>
                </xsl:call-template>
            </xsl:when>
            <xsl:otherwise>
                <xsl:value-of select="$pString"/>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>
</xsl:stylesheet>

Output:

<FullRequest>
    <Header>
        <Looptimes>3</Looptimes>
        <SomeElement>blah!</SomeElement>
        <AnotherElement>blah!!</AnotherElement>
    </Header>
    <RequestDetail>
        <!-- Request Element is a string of fixed length (50 characters) -->
        <Request>THE QUICKABCOWXYZOXFGKMPS OVER THE LAZY DOG AGAIN!</Request>
        <Request>THE TIME 123 JYOKEDDSLER THE LAZY DOG, PROGRESSED!</Request>
        <Request>OWING TO BAT WTKRSPLAFD KNOWLEDGE OF THE PHRASE AN</Request>
    </RequestDetail>
</FullRequest>
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号