使用XSLT更新属性

时间:2013-10-08 15:06:05

标签: xml xslt

我是XSLT的新手。 我试图将XML的当前int更新为大于25的XML到1-25范围内的唯一ID。

*的 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>

我的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>

输出/转换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>

查询 1.如何更新属性InstanceID而不是附加其他元素 2.如何跟踪生成/分配/新生成的实例Id,以避免重复。

提前致谢,任何帮助都会很明显。

2 个答案:

答案 0 :(得分:1)

您已经使用身份模板开始了正确的方式,但后来我不明白您下一步要做什么。你有这个:

match="Profile/*"

但我在源文档中看不到任何名为Profile的元素。我期望从您对问题的描述中看到的是这样的:

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

其中xxxx是属性的新值;这就是问题的下一部分。这不是特别容易,但你似乎有计算变量$ pstart的所有逻辑,这似乎是你想要的值,所以只需将其用作上面的xxxxx。

答案 1 :(得分:0)

让我们尝试解决分配唯一ID的问题。这个很难,很高兴知道真正的要求是什么,因为它可能过度约束。

我认为,我会首先使用初始传递来确定正在使用的标识符,并生成包含可供使用的标识符的XML文档。这并不太难:基本上(在伪代码中)“对于我在1到N的地方没有(我在输入中出现)返回i”。

然后我将构建一个需要更改标识符的节点列表,将此列表放在一个变量中;然后使用此变量作为参数进行文档的树形遍历;当列表中存在节点时,作为列表中的第N个项目,将标识符替换为“免费使用”列表中第N个标识符的id。

我不会尝试使用XSLT 1.0。但是,我不会尝试使用XSLT 1.0;一旦你习惯了2.0,那就太辛苦了。另外,请不要让我将此算法转换为XSLT代码;如果你不能自己做,你应该付钱给别人为你做。