Update XML Attributes based on specific attribute

2019-08-31 07:01发布

问题:

In my Source XML i am reassigning all the Instance ID from numbers 1 to onwards (till there existence). I am updating Apple, Mango, Banana InstanceId's with above values under Profile element. Here i ignore Profile InstanceID level occurrence. My requirement is to trigger these xslt code only when at least one instance id in a given set of "Profile" is greater than 25.

<Root>
  <Properties>
    <Props></Props>
    <Input></Input>
    <Profile InstanceID="4" ObjectID="XYZ">
      <foo>Profile 1</foo><!-- Need to update these set as atleast one instanceID is greater than 25 -->
      <Apple InstanceID="26" ObjectID="ABC" Type="103"></Apple>
      <Mango InstanceID="1" ObjectID="DEF" Type="103"></Mango>
      <Mango InstanceID="27" ObjectID="GHI" Type="103"></Mango>
      <Banana InstanceID="29" ObjectID="GHI1" Type="103"></Banana>
    </Profile>
  </Properties>
  <Properties>
    <Props></Props>
    <Input></Input>
    <Profile InstanceID="4" ObjectID="XYZ">
      <foo>Profile 1</foo><!-- no need to update these set as no instanceID is greater than 25 -->
      <Apple InstanceID="21" ObjectID="MNO" Type="103"></Apple>
      <Mango InstanceID="21" ObjectID="PQR" Type="103"></Mango>
      <Mango InstanceID="23" ObjectID="EFG" Type="103"></Mango>
      <Mango InstanceID="24" ObjectID="EFG123" Type="103"></Mango>
      <Banana InstanceID="25" ObjectID="GHI1" Type="103"></Banana>
    </Profile>
  </Properties>
</Root>

Below is the XSLT i used

# 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>
  <xsl:template match="Profile/*/@InstanceID">
    <xsl:attribute name="InstanceID">
      <xsl:value-of select="count(../preceding-sibling::*[@InstanceID]) + 1" />
    </xsl:attribute>
  </xsl:template>
</xsl:stylesheet>

And these is Output/Transformed XML

# Transformed XML #
<Root>
  <Properties>
    <Props></Props>
    <Input></Input>
    <Profile InstanceID="4" ObjectID="XYZ"><!-- no need to update these instanceID -->
      <foo>Profile 1</foo>
      <Apple InstanceID="1" ObjectID="ABC" Type="103"></Apple>
      <Mango InstanceID="2" ObjectID="DEF" Type="103"></Mango>
      <Mango InstanceID="3" ObjectID="GHI" Type="103"></Mango>
      <Banana InstanceID="4" ObjectID="GHI1" Type="103"></Banana>
    </Profile>
  </Properties>
  <Properties>
    <Props></Props>
    <Input></Input>
    <Profile InstanceID="4" ObjectID="XYZ"><!-- no need to update these instanceID -->
      <foo>Profile 1</foo>
      <Apple InstanceID="1" ObjectID="MNO" Type="103"></Apple>
      <Mango InstanceID="2" ObjectID="PQR" Type="103"></Mango>
      <Mango InstanceID="3" ObjectID="EFG" Type="103"></Mango>
      <Mango InstanceID="4" ObjectID="EFG123" Type="103"></Mango>
      <Banana InstanceID="5" ObjectID="GHI1" Type="103"></Banana>
    </Profile>
  </Properties>
</Root>

回答1:

My requirement is to trigger these xslt code only when at least one instance id in a given set of "Profile" is greater than 25

You simply need to make your Profile/*/@InstanceID template slightly more specific. At the moment it applies to InstanceID attributes on child elements of all Profile elements, you need to add a predicate at the Profile level to restrict it to certain profiles only:

<xsl:template match="Profile[*/@InstanceID &gt; 25]/*/@InstanceID">

This works because a comparison operator where one side is a node set is true if any of the nodes in the set satisfy the required condition, so in this case if any of the child elements has an InstanceID greater than 25.



标签: xml xslt