简体   繁体   中英

Updating attributes using XSLT

I am new to XSLT. I am trying to update the ID's present int following XML which are greatert than 25 to a unique id in a range of 1-25.

* MYXML *

<Root>
<Properties>
<Props></Props>
<Input>
</Input>
<Profile InstanceID ="4" ObjectID="XYZ"> (no need to update these instanceID)
<ELM_INT>Profile 1</ELM_INT>
<Video **InstanceID="26"** ObjectID="ABC" Type="103"></Video>   
<Audio **InstanceID="1"** ObjectID="DEF" Type="103"></Audio>
<Audio **InstanceID="27"** ObjectID="GHI" Type="103"></Audio>      
<Output ObjectID="JKL" Type="104" Type="25"></Output>
</Profile>
</Properties>

<Properties>
<Props></Props>
<Input>
</Input>
<Profile InstanceID ="4" ObjectID="XYZ"> (no need to update these instanceID)
<ELM_INT>Profile 1</ELM_INT>
<Video **InstanceID="33"** ObjectID="MNO" Type="103"></Video>
<Audio **InstanceID="25"** ObjectID="PQR" Type="103"></Audio>
<Audio **InstanceID="2"** ObjectID="EFG" Type="103"></Audio>      
<Output ObjectID="HIJ" Type="104" Type="25"></Output>
</Profile>
</Properties>
</Root>

My XSLT

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl">

<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>

<!--Main START-->
<xsl:template name="Main" match="Profile/*">
<xsl:copy>
<xsl:apply-templates select="@*|node()" />
</xsl:copy>

<!--Get all instance id's includng Profile and call loop-->
<xsl:for-each select="@*/..">
<!--Id instanceId is greater than 25 than call loop-->
<xsl:variable name="CurrentInstanceID">
<xsl:value-of select="@InstanceID"/>
</xsl:variable>


<xsl:if test="$CurrentInstanceID &gt; 25">
<!--<xsl:text> .Calling Iterate1To25 </xsl:text>-->  
<xsl:call-template name="Iterate1To25">
<xsl:with-param name="pStart" select="1"/>
<xsl:with-param name="pEnd" select="25"/>
</xsl:call-template>
</xsl:if>

</xsl:for-each>

</xsl:template>
<!--Main END-->

<!-- Iterate1To25which iterate for 25 times START-->
<xsl:template name="Iterate1To25" >
<xsl:param name="pStart"/>
<xsl:param name="pEnd"/>

<xsl:if test="not($pStart &gt; $pEnd)">

<xsl:variable name="serchAudeoInstanceID">
<xsl:value-of select="count(../Audio[@InstanceID=$pStart])"/>
</xsl:variable>

<xsl:variable name="serchVideoInstanceID">
<xsl:value-of select="count(../Video[@InstanceID=$pStart])"/>
</xsl:variable>

<xsl:choose>
<xsl:when test="$serchAudeoInstanceID &gt; 0 or $serchVideoInstanceID &gt; 0>
<xsl:call-template name="Iterate1To25">
<xsl:with-param name="pStart" select="$pStart+1"/>
<xsl:with-param name="pEnd" select="25"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<!--pStart can be assigned-->
<xsl:element name="Valid_ID">
<xsl:value-of select="$pStart"/>
<xsl:attribute name="InstanceID">
<xsl:value-of select="$pStart"/>
</xsl:attribute>
</xsl:element>

</xsl:otherwise>
</xsl:choose>

</xsl:if>

</xsl:template>

</xsl:stylesheet>

OUTPUT/Transformed XML

<Root>
<Properties>
<Props></Props>
<Input>
</Input>
<Profile_InstanceID ="4" ObjectID="XYZ">
<ELM_INT>Profile 1</ELM_INT>

<Video **InstanceID="26"** ObjectID="ABC" Type="103"></Video> 
****<ValidID>2</ValidID>****

<Audio **InstanceID="1"** ObjectID="DEF" Type="103"></Audio>

<Audio **InstanceID="27"** ObjectID="GHI" Type="103"></Audio>      
****<ValidID>2</ValidID> (expected 3)****

<Output ObjectID="JKL" Type="104" Type="25"></Output>
</Profile_Instance>
</Properties>

<Properties>
<Props></Props>
<InputTransport>
</InputTransport>
<Profile_InstanceID ="4" ObjectID="XYZ">
<ELM_INT>Profile 1</ELM_INT>

<Video **InstanceID="33"** ObjectID="MNO" Type="103"></Video>
****<ValidID>1</ValidID>****

<Audio **InstanceID="25"** ObjectID="PQR" Type="103"></Audio>

<Audio **InstanceID="2"** ObjectID="EFG" Type="103"></Audio>      

<Output ObjectID="HIJ" Type="104" Type="25"></Output>
</Profile_Instance>
</Properties>
</Root>

Query 1. How to update attribute InstanceID instead of appending an additional element 2. How to keep track of generated/allocated/Newly generated instance Id's so that duplication is avoided.

Thanks in advance, any help would be appreciable.

You've started the right way with an identity template, but then I don't understand what you're trying to do next. You've got this:

match="Profile/*"

but I don't see any elements named Profile in your source document. What I would expect to see from your description of the problem is something like this:

<xsl:template match="@InstanceID[. > 25]">
  <xsl:attribute name="InstanceId" select="xxxx"/>
</xsl:template>

where xxxx is the new value of the attribute; and that's the next part of the problem. It's not particularly easy, but you seem to have all the logic there to compute variable $pstart and this seems to be the value you want, so just use it as xxxxx above.

Let's try to address the question of allocating unique IDs. This one is quite difficult, and it would be nice to know what the real requirement is, because it may be over-constrained.

I would start, I think, with an initial pass that determines what identifiers are in use, and generates an XML document containing identifiers that are free for use. That's not too difficult: essentially (in pseudo-code) "for i in 1 to N where not(i present in input) return i".

Then I would build a list of nodes whose identifiers need to be changed, putting this list in a variable; and then do a tree-walk of the document with this variable available as a parameter; when a node is present in the list, as the Nth item in the list, replace the identifier with the id that is the Nth identifier in the "free-to-use" list.

I wouldn't attempt this with XSLT 1.0. But then, I wouldn't attempt anything with XSLT 1.0; it's just too much like hard work, once you've got used to 2.0. Also, please don't ask me to translate this algorithm into XSLT code; if you can't do it yourself, you should pay someone else to do it for you.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM