Rectangle 27 2

Assuming all your XML file were actually well-formed, you should start off by using the XSLT identity transform

<xsl:template match="@*|node()">
    <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
</xsl:template>
xsl:for-each
<xsl:apply-templates select="document('File1')/ds/sk" />
<xsl:apply-templates select="document('File2')/ds/ac" />
<xsl:apply-templates select="document('File3')/ds/rs" />

Note, you may not necessarily need to use the document function on File1 if that happens to be the input file of the XSLT itself.

<xsl:template match="*[not(*)][not(normalize-space())]" />
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:output method="xml" encoding="UTF-8" indent="yes" />

     <xsl:template match="/">
         <xsl:apply-templates select="document('File1')/ds/sk" />
         <xsl:apply-templates select="document('File2')/ds/ac" />
         <xsl:apply-templates select="document('File3')/ds/rs" />
     </xsl:template>

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

    <xsl:template match="*[not(*)][not(normalize-space())]" />
</xsl:transform>

Thks, I have tried the given xslt, but no xml is outputted at all. note : there was a mistake in my initial post, I was using copy-of instead of for-each ... and i'm using msxml to transform.

Feel free to amend your initial post to correct your mistake. Also, I've made a small edit to my answer. You do need to make sure the document function references the correct file path for each file. If you enter just File1.xml it will (probably) look for the XML in the same folder as the XSLT. Thanks!

File1.xml is located in the same directory, but I use absolut path anyway. I was using c:\test\File1.xml, tried with file:///c:/test/File1.xml, the result is the same, no output file...

xsl:apply-templates
xsl:copy-of

How to merge xml files using xslt and remove empty elements - Stack Ov...

xml xslt xpath merge
Rectangle 27 3

Then the elements which has sequence attr, they should be at that exact position. Then void position should get filled by the natural order of remaining element.(i.e. by the elements which don't have sequence attr., from default.xml)

IMHO, this is not a sorting problem, but a queuing problem. Let us simplify the example by having members of two types: placed members, whose place in the queue is reserved, and ordinary members that need to fill the gaps between the placed members.

<members>
    <member id="1" place="9"/>
    <member id="2" place="2"/>
    <member id="3" place="5"/>
    <member id="4"/>
    <member id="5"/>
    <member id="6"/>
    <member id="7"/>
    <member id="8"/>
    <member id="9"/>
    <member id="10"/>
    <member id="11"/>
    <member id="12"/>
</members>

The queuing algorithm could be described as follows:

Each reserved member "calls" a group of ordinary members to be seated ahead of it.

The size of this group is equal to the size of the gap between the current member's reserved place and the place of its preceding reserved sibling. That's 9 - 5 - 1 = 3 in our example.

The starting position of this group can be deduced as follows: since the preceding member's reserved place is #5, then 5 members have already been seated; out of these, 2 members (at places #2 and #5) are reserved members, therefore only 3 ordinary members have been seated and our group starts at position 5 - 3 + 1 = 4.

The last reserved member calls the rest of the ordinary members to be seated after it.

Here's an example of implementation in XSLT 1.0:

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:exsl="http://exslt.org/common"
extension-element-prefixes="exsl">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>

<xsl:variable name="reserved-members">
    <xsl:for-each select="/members/member[@place]">
        <xsl:sort select="@place" data-type="number" order="ascending"/>
        <xsl:copy-of select="."/>
    </xsl:for-each>
</xsl:variable>

<xsl:variable name="ordinary-members" select="/members/member[not(@place)]"/>

<xsl:template match="/">
    <output>
        <xsl:for-each select="exsl:node-set($reserved-members)/member">

            <xsl:variable name="previous-place"> 
                <xsl:choose>
                    <xsl:when test="position()>1">
                        <xsl:value-of select="preceding-sibling::member[1]/@place"/>
                    </xsl:when>
                    <xsl:otherwise>
                        <xsl:value-of select="0"/>
                    </xsl:otherwise>
                </xsl:choose>
            </xsl:variable>

            <xsl:variable name="gap-size" select="@place - $previous-place - 1"/>
            <xsl:variable name="gap-start" select="$previous-place - count(preceding-sibling::member) + 1"/> 

            <!-- fill the gap with ordinary members -->
            <xsl:for-each select="$ordinary-members[$gap-start &lt;= position() and position() &lt; $gap-start + $gap-size]">
                <xsl:copy-of select="."/>
            </xsl:for-each>

            <!-- output the reserved member -->
            <member id="{@id}" place="{@place}" start="{$gap-start}" size="{$gap-size}"/>

            <!-- output remaining ordinary members -->
            <xsl:if test="position()=last()">
                <xsl:for-each select="$ordinary-members[position() >= $gap-start + $gap-size]">
                    <xsl:copy-of select="."/>
                </xsl:for-each>
            </xsl:if>

        </xsl:for-each>
    </output>
</xsl:template>

</xsl:stylesheet>

When applied to the above input example, the result is:

<?xml version="1.0" encoding="UTF-8"?>
<output>
   <member id="4"/>
   <member id="2" place="2" start="1" size="1"/>
   <member id="5"/>
   <member id="6"/>
   <member id="3" place="5" start="2" size="2"/>
   <member id="7"/>
   <member id="8"/>
   <member id="9"/>
   <member id="1" place="9" start="4" size="3"/>
   <member id="10"/>
   <member id="11"/>
   <member id="12"/>
</output>

thanks for this solution, but problem is I have to use this logic 5-6times in my program, so instead of doing this every time, Can we make something like list (of id, in comma separated string) and then de-tokenized in that list for loop ?

@BhushanPatil I suppose you could write it out as a function or a processing template. It's not something I'm interested in doing, though.

Sorting in XSLT from two xml files - Stack Overflow

xml xslt xpath xslt-2.0
Rectangle 27 3

Then the elements which has sequence attr, they should be at that exact position. Then void position should get filled by the natural order of remaining element.(i.e. by the elements which don't have sequence attr., from default.xml)

IMHO, this is not a sorting problem, but a queuing problem. Let us simplify the example by having members of two types: placed members, whose place in the queue is reserved, and ordinary members that need to fill the gaps between the placed members.

<members>
    <member id="1" place="9"/>
    <member id="2" place="2"/>
    <member id="3" place="5"/>
    <member id="4"/>
    <member id="5"/>
    <member id="6"/>
    <member id="7"/>
    <member id="8"/>
    <member id="9"/>
    <member id="10"/>
    <member id="11"/>
    <member id="12"/>
</members>

The queuing algorithm could be described as follows:

Each reserved member "calls" a group of ordinary members to be seated ahead of it.

The size of this group is equal to the size of the gap between the current member's reserved place and the place of its preceding reserved sibling. That's 9 - 5 - 1 = 3 in our example.

The starting position of this group can be deduced as follows: since the preceding member's reserved place is #5, then 5 members have already been seated; out of these, 2 members (at places #2 and #5) are reserved members, therefore only 3 ordinary members have been seated and our group starts at position 5 - 3 + 1 = 4.

The last reserved member calls the rest of the ordinary members to be seated after it.

Here's an example of implementation in XSLT 1.0:

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:exsl="http://exslt.org/common"
extension-element-prefixes="exsl">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>

<xsl:variable name="reserved-members">
    <xsl:for-each select="/members/member[@place]">
        <xsl:sort select="@place" data-type="number" order="ascending"/>
        <xsl:copy-of select="."/>
    </xsl:for-each>
</xsl:variable>

<xsl:variable name="ordinary-members" select="/members/member[not(@place)]"/>

<xsl:template match="/">
    <output>
        <xsl:for-each select="exsl:node-set($reserved-members)/member">

            <xsl:variable name="previous-place"> 
                <xsl:choose>
                    <xsl:when test="position()>1">
                        <xsl:value-of select="preceding-sibling::member[1]/@place"/>
                    </xsl:when>
                    <xsl:otherwise>
                        <xsl:value-of select="0"/>
                    </xsl:otherwise>
                </xsl:choose>
            </xsl:variable>

            <xsl:variable name="gap-size" select="@place - $previous-place - 1"/>
            <xsl:variable name="gap-start" select="$previous-place - count(preceding-sibling::member) + 1"/> 

            <!-- fill the gap with ordinary members -->
            <xsl:for-each select="$ordinary-members[$gap-start &lt;= position() and position() &lt; $gap-start + $gap-size]">
                <xsl:copy-of select="."/>
            </xsl:for-each>

            <!-- output the reserved member -->
            <member id="{@id}" place="{@place}" start="{$gap-start}" size="{$gap-size}"/>

            <!-- output remaining ordinary members -->
            <xsl:if test="position()=last()">
                <xsl:for-each select="$ordinary-members[position() >= $gap-start + $gap-size]">
                    <xsl:copy-of select="."/>
                </xsl:for-each>
            </xsl:if>

        </xsl:for-each>
    </output>
</xsl:template>

</xsl:stylesheet>

When applied to the above input example, the result is:

<?xml version="1.0" encoding="UTF-8"?>
<output>
   <member id="4"/>
   <member id="2" place="2" start="1" size="1"/>
   <member id="5"/>
   <member id="6"/>
   <member id="3" place="5" start="2" size="2"/>
   <member id="7"/>
   <member id="8"/>
   <member id="9"/>
   <member id="1" place="9" start="4" size="3"/>
   <member id="10"/>
   <member id="11"/>
   <member id="12"/>
</output>

thanks for this solution, but problem is I have to use this logic 5-6times in my program, so instead of doing this every time, Can we make something like list (of id, in comma separated string) and then de-tokenized in that list for loop ?

@BhushanPatil I suppose you could write it out as a function or a processing template. It's not something I'm interested in doing, though.

Sorting in XSLT from two xml files - Stack Overflow

xml xslt xpath xslt-2.0
Rectangle 27 3

The optimal solution for this problem with Xslt 1.0 would be to use Muenchian grouping. (Given that the elements are already sorted by the ValidFromDate attribute) the following stylesheet should do the trick:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" indent="yes"/>

  <xsl:key name="element-key" match="/SomeData/*" use="name()" />

  <xsl:template match="/SomeData">
    <xsl:copy>
      <xsl:for-each select="*[generate-id() = generate-id(key('element-key', name()))]">
        <xsl:copy-of select="(. | following-sibling::*[name() = name(current())])[last()]" />
      </xsl:for-each>
    </xsl:copy>
  </xsl:template>

</xsl:stylesheet>

Here is the result I got when running it against your sample Xml:

<?xml version="1.0" encoding="utf-8"?>
<SomeData>
  <A ValidFromDate="2012-01-19">A_2</A>
  <B ValidFromDate="2012-01-19">B_3</B>
  <C ValidFromDate="2011-01-20">C_2</C>
</SomeData>

Hi, I made a modification to your answer. Both produce the same output given the OP's source XML, but I can't tell if there are more subtle differences.

There should not be any differences. Your version is much cleaner! Thanks!

@Pawel: Actually, the elements aren't sorted -- thus this solution is not correct.

xml - Need XSLT transform to remove duplicate elements - sorted by an ...

xml xslt xpath biztalk
Rectangle 27 2

If you can ensure the duplicate nodes are always consecutive, then the simplest way to do this is build upon the XSTL Identity Transform an just have an extra template to strip out the templates like so

<xsl:template 
     match="*[not(*)]
             [name() = preceding-sibling::*[1]/name()]
             [@value = preceding-sibling::*[1]/@value]" />

This matches any child element, and ignores it if it has the same name and value as the previous element. There is no need to hard-code an element name anywhere in this case.

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" indent="yes" />

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

  <xsl:template match="*[not(*)][name() = preceding-sibling::*[1]/name()][@value = preceding-sibling::*[1]/@value]" />
</xsl:stylesheet>

However this would fail if your XML looked like this, and your duplicate nodes were consecutive

<Samsung>
         <name value="galaxy"/>
         <name value="galaxys"/>
         <id value="123"/>
         <name value="galaxy"/>
         <id value="123"/>
         <name2 value="galaxy"/>
       </Samsung>

You could fix this by changing the template to check back all previous nodes

<xsl:template match="*[not(*)]
                      [name() = preceding-sibling::*/name()]
                      [@value = preceding-sibling::*/@value]" />

However, this starts to become inefficient with large numbers of elements. If you have hundred of elements, then each precedinig-sibling check will repeatedly involve checking hundred of elements (i.e the 100th element has to check 99 preceding ones, the 101th element checks 100 ones, etc).

A more efficient method (in XSLT1.0) is to use a technique called Muenchian Grouping. It is certainly something worth learning about if you use XSLT a lot.

First you define a key to 'group' your elements. In this case, your are looking for distinct elements defined by their parent, element name, and value

<xsl:key name="duplicate" match="*[not(*)]" use="concat(generate-id(..), '|', name(), '|', @value)" />

Then to ignore the duplicates, you match any element that doesn't occur in the first position in the key for the given 'lookup' value

<xsl:template match="*[not(*)]
                      [generate-id() != 
                      generate-id(key('duplicate', concat(generate-id(..), '|', name(), '|', @value))[1])]" />

Here is the full XSLT in this case

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" indent="yes" />
    <xsl:key name="duplicate" match="*[not(*)]" use="concat(generate-id(..), '|', name(), '|', @value)" />

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

 <xsl:template match="*[not(*)][generate-id() != generate-id(key('duplicate', concat(generate-id(..), '|', name(), '|', @value))[1])]" />

</xsl:stylesheet>

Very god answer. I thought about something like this, but was to lazy. But wouldn't it be even better to use generate-id(..) instead of name(..) as key? Then in would also work with more same named parent nodes.

I tried the code, but it's deleting every element not just duplicates. Am I doing anything wrong?

The original XML in your question is not actually well-formed, which suggests you are using different XML to what you have shown us. If you could show us a more accurate sample, one that is not getting the results you want, that may help. Thanks!

<?xml version="1.0" encoding="UTF-8"?> <check> 	<val> 		<Samsung> 			<name value="galaxy" /> 			<name value="galaxy" /> 			<name value="galaxys" /> 			<id value="123" /> 			<id value="123" /> 			<name2 value="galaxy" /> 		</Samsung>  		<htc> 			<name value="galaxy" /> 			<name value="galaxy" /> 			<name value="galaxys" /> 			<id value="123" /> 			<id value="123" /> 			<name2 value="galaxy" /> 		</htc> 	</val> </check>

java - How to remove duplicates in xml files using xslt? - Stack Overf...

java xml xslt xml-parsing xslt-1.0
Rectangle 27 3

This can be done with a single override of the identity template...

<HitList>
    <Hit System="A" ID="1"/>
    <Hit System="A" ID="2"/>
    <Hit System="A" ID="2"/>
    <Hit System="B" ID="1"/>
    <Hit System="B" ID="2"/>
    <Hit System="B" ID="3"/>
    <Hit System="B" ID="4"/>
</HitList>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output indent="yes"/>
    <xsl:strip-space elements="*"/>

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

    <xsl:template match="Hit[(@System='B' and @ID=../Hit[@System='A']/@ID) or 
        @ID = preceding-sibling::Hit[@System='A']/@ID]"/>

</xsl:stylesheet>
<HitList>
   <Hit System="A" ID="1"/>
   <Hit System="A" ID="2"/>
   <Hit System="B" ID="3"/>
   <Hit System="B" ID="4"/>
</HitList>

Removing Duplicate Elements from my XML file by using an XSLT - Stack ...

xml xslt
Rectangle 27 3

Here is an efficient XSLT 1.0 solution using keys:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:key name="kHitById" match="Hit" use="@ID"/>
 <xsl:key name="kHitAById" match="Hit[@System = 'A']" use="@ID"/>

 <xsl:template match=
  "Hit[generate-id() = generate-id(key('kHitById',@ID)[1])]">

  <xsl:copy-of select=
  "key('kHitAById', @ID)[1]|current()[not(key('kHitAById', @ID))]"/>
 </xsl:template>
</xsl:stylesheet>

When this transformation is applied on the following XML document (intentionally adapted from the provided one, to make it more interesting by placing some Bs before the corresponding As):

<HitList>
   <Hit System="B" ID="1"/>
   <Hit System="A" ID="1"/>
   <Hit System="B" ID="2"/>
   <Hit System="A" ID="2"/>
   <Hit System="A" ID="2"/>
   <Hit System="B" ID="3"/>
   <Hit System="B" ID="4"/>
</HitList>

the wanted, correct result is produced:

<Hit System="A" ID="1"/>
<Hit System="A" ID="2"/>
<Hit System="B" ID="3"/>
<Hit System="B" ID="4"/>

Whith java 7/groovy I get this cryptik exception : ERROR: 'Erreur lors de la vrification du type de l'expression 'filter-expr(funcall(current, []), [pred(funcall(not, [funcall(key, [literal-expr(kHitAById), step("attribute", 15)])]))])'.' Exception in thread "main" javax.xml.transform.TransformerConfigurationException I can't even translate in english ! My feeling is current()[not(key('kHitAById', @ID))] doesn't work, I don't know why.

@Istao, Don't use incompliant/buggy XSLT processors. This solution works with any compliant XSLT processors -- on all eleven different XSLT processors I use daily on my computer: MSXML (3,4,6), Saxon (6.5.4 and 9.x), Altova (XMLSpy) for XSLT 1.0 and 2.0, XQSharp (XMLPrime).

@Dimitre - If a use this as a secondary transform, how can I retain the 'HitList' root element?

<xsl:template match="/*"><xsl:copy><xsl:apply-templates/></xsl:copy></xsl:template>

@Dimitre - I answered my own question above concerning adding the root element back. I do have another question. I always want sytem 'A' results ahead of system 'B' results. Your solution puts 'A' in front of 'B' when they start there and when there is a duplicate. However, if 'B' has a unique ID and was ahead of 'A' to start, it will remain ahead of 'A'. I am accepting your answer but was wondering your thoughts on this.

Removing Duplicate Elements from my XML file by using an XSLT - Stack ...

xml xslt
Rectangle 27 10

I had to tweak to get VS2010 Professional to show Intellisense for XSLT 2.0. First, download the file http://www.w3.org/2007/schema-for-xslt20.xsd. You'll then need to edit the file and remove 'schemaLocation' attributes from both 'xsl:import' elements which are located at the beginning of the document after the comments. Then copy this modified file to [Your Visual Studio 10.0 Installation Folder]\Xml\Schemas. If you have VS running restart it. Open your XSLT file so that the XML menu is visible and goto 'XML->Schemas...'. There you will find both version 1.0 and 2.0 schemas for XSLT. You'll need to disable version 1.0 by clicking under its 'Use' field and selecting 'Don't use this scheme'. Now the Intellisense should work.

The requirement to remove 'schemaLocation' attribute may have something to do with .NET security blocking XML documents from retrieving documents from web. I'm not sure. Anyways, the files are available locally so this shouldn't be any problem.

The editor should have selected the version 2.0 of the schema by looking at <xsl:stylesheet version="2.0"...> but I'm not a XML guru so there may be a better workaround than disabling schema version 1.0.

@John Saunders : I tried the same its not working for me.

@Sanjeev:It also not working for me... what else i missed?...

xml - XSLT 2.0 intellisense in Visual Studio 2010 - Adding a schema? -...

xml visual-studio xslt xsd
Rectangle 27 10

I had to tweak to get VS2010 Professional to show Intellisense for XSLT 2.0. First, download the file http://www.w3.org/2007/schema-for-xslt20.xsd. You'll then need to edit the file and remove 'schemaLocation' attributes from both 'xsl:import' elements which are located at the beginning of the document after the comments. Then copy this modified file to [Your Visual Studio 10.0 Installation Folder]\Xml\Schemas. If you have VS running restart it. Open your XSLT file so that the XML menu is visible and goto 'XML->Schemas...'. There you will find both version 1.0 and 2.0 schemas for XSLT. You'll need to disable version 1.0 by clicking under its 'Use' field and selecting 'Don't use this scheme'. Now the Intellisense should work.

The requirement to remove 'schemaLocation' attribute may have something to do with .NET security blocking XML documents from retrieving documents from web. I'm not sure. Anyways, the files are available locally so this shouldn't be any problem.

The editor should have selected the version 2.0 of the schema by looking at <xsl:stylesheet version="2.0"...> but I'm not a XML guru so there may be a better workaround than disabling schema version 1.0.

@John Saunders : I tried the same its not working for me.

@Sanjeev:It also not working for me... what else i missed?...

xml - XSLT 2.0 intellisense in Visual Studio 2010 - Adding a schema? -...

xml visual-studio xslt xsd
Rectangle 27 1

As well as removing the duplicate "temperatureInformation" elements, for each such distinct element it looks like you want to merge the distinct "temperatureStats" elements for all elements in the group.

As this is a second level of grouping, the key for this will need to take into the first level of grouping too, and so look like this:

<xsl:key name="grouptemperatureStats" 
         match="party/pos/attrGroupMany[@name = 'temperatureInformation']/row/attrGroupMany[@name = 'temperatureStats']/row"
         use="concat(generate-id(ancestor::pos), '|', ../../../attr[@name = 'temperatureCode'], '|', ../../../attrQualMany[@name = 'temperature'], '|', attr[@name = 'StatsCode'])"/>

To use it, in a template matching the "temperatureStats" element, you would first select all the elements in the current parent group

<xsl:variable name="group" 
                  select="key('grouptemperatureInformation', concat(generate-id(ancestor::pos), '|', ../attr[@name = 'temperatureCode'], '|', ../attrQualMany[@name = 'temperature']))/attrGroupMany[@name='temperatureStats']/row" />

Then you could then select the distinct "temperatureStats" elements within this using the second key

<xsl:apply-templates select="@* | $group[generate-id() = generate-id(key('grouptemperatureStats', concat(generate-id(ancestor::pos), '|', ../../../attr[@name = 'temperatureCode'], '|', ../../../attrQualMany[@name = 'temperature'], '|', attr[@name = 'StatsCode']))[1])]"/>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:key name="grouptemperatureInformation" 
             match="party/pos/attrGroupMany[@name = 'temperatureInformation']/row"
             use="concat(generate-id(ancestor::pos), '|', attr[@name = 'temperatureCode'], '|', attrQualMany[@name = 'temperature'])"/>

    <xsl:key name="grouptemperatureStats" 
             match="party/pos/attrGroupMany[@name = 'temperatureInformation']/row/attrGroupMany[@name = 'temperatureStats']/row"
             use="concat(generate-id(ancestor::pos), '|', ../../../attr[@name = 'temperatureCode'], '|', ../../../attrQualMany[@name = 'temperature'], '|', attr[@name = 'StatsCode'])"/>

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

    <xsl:template match="attrGroupMany[@name = 'temperatureInformation']">
        <xsl:copy>
            <xsl:apply-templates select="@*"/>
            <xsl:apply-templates select="row[generate-id() = generate-id(key('grouptemperatureInformation', concat(generate-id(ancestor::pos), '|', attr[@name = 'temperatureCode'], '|', attrQualMany[@name = 'temperature']))[1])]"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="attrGroupMany[@name = 'temperatureStats']">
        <xsl:variable name="group" select="key('grouptemperatureInformation', concat(generate-id(ancestor::pos), '|', ../attr[@name = 'temperatureCode'], '|', ../attrQualMany[@name = 'temperature']))/attrGroupMany[@name='temperatureStats']/row" />
        <xsl:copy>
            <xsl:apply-templates select="@* | $group[generate-id() = generate-id(key('grouptemperatureStats', concat(generate-id(ancestor::pos), '|', ../../../attr[@name = 'temperatureCode'], '|', ../../../attrQualMany[@name = 'temperature'], '|', attr[@name = 'StatsCode']))[1])]"/> 
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

Thanks It worked. At one place extra ../ was used which I have edited and removed.

xml - Removing duplicates in parent and child entity in XSLT - Stack O...

xml xslt xslt-1.0
Rectangle 27 1

Assuming you don't have duplicates in your files, this is not actually that complicated.

As you are not transforming the item elements at all, you start off by using the identity template

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

Then, you only need to write a template to match the root element (of the first XML document), because you will be changing it by adding and re-ordering its child nodes.

In terms of merging it, just write an xsl:apply-templates to select the item elements of the current root element, and the item elements in the second XML file. This can be used in conjunction with xsl:sort instructions.

<xsl:apply-templates select="item|document($mergeFile)/root/item">
        <xsl:sort select="flag" />
        <xsl:sort select="number" data-type="number" />
        <xsl:sort select="name" />
     </xsl:apply-templates>

Note the use of the document function to read the second XML file. In this case $mergeFile is a parameter set to the location of the second file you wish to merge with the first file currently being acted on by the XML.

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
   <xsl:output method="xml" indent="yes"/>
   <xsl:param name="mergeFile" select="'Test2.xml'" />

   <xsl:template match="/*">
      <xsl:copy>
         <xsl:apply-templates select="item|document($mergeFile)/root/item">
            <xsl:sort select="flag" />
            <xsl:sort select="number" data-type="number" />
            <xsl:sort select="name" />
         </xsl:apply-templates>
      </xsl:copy>
   </xsl:template>

   <xsl:template match="@*|node()">
      <xsl:copy>
         <xsl:apply-templates select="@*|node()"/>
      </xsl:copy>
   </xsl:template>
</xsl:stylesheet>

First, thanks for responding to me instead of downvoting and moving on like others seem to have done. The downvote trolls that are all over stackoverflow are one reasons I am hesitant to post here. Second, can you explain how I would go about executing the above script? I've found ways to do it but they seem only to work with one file. I'm not sure how to pass along the second file.

There are many ways to execute the above script, depending on what platform you are using. C#, php, Java, JavaScript, etc. Although the process with will require you to apply the XSLT to a single file initially, the "document" function allows it to access another. You don't actually pass the second file itself, but you pass the file name (possibly with the full file path it is sits in another directory). So, its best to look up how to pass a parameter to XSLT for the method you are using.

sorting - Merge then sort two xml files - Stack Overflow

xml sorting xslt merge
Rectangle 27 1

The following assumes you simply want to output the member elements, it uses a recursive function to construct the right sequence from the original elements, either using an element for which a position is defined in the rules.xml or filling the position with the next remaining element:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:xs="http://www.w3.org/2001/XMLSchema"
  exclude-result-prefixes="xs mf"
  xmlns:mf="http://example.com/mf">

<xsl:param name="rules-uri" select="'Rules.xml'"/>
<xsl:variable name="rules-doc" select="doc($rules-uri)"/>

<xsl:variable name="main-input" select="/"/>

<xsl:output indent="yes"/>

<xsl:key name="member" match="list_view/members/member" use="@name"/>

<xsl:key name="pos" match="list_view/members/member" use="xs:integer(@sequence)"/>

<xsl:variable name="exclude" select="key('member', $rules-doc//exclude/members/member/@name)"/>

<xsl:variable name="process" select="//list_view/members/member except $exclude"/>

<xsl:variable name="no-key" select="$process[not(key('member', @name, $rules-doc))]"/>

<xsl:function name="mf:fill" as="element(member)*">
  <xsl:param name="pos" as="xs:integer"/>
  <xsl:param name="length" as="xs:integer"/>
  <xsl:param name="no-key" as="element(member)*"/>
  <xsl:sequence select="if ($pos gt $length)
                        then ()
                        else 
                          (if (key('pos', $pos, $rules-doc))
                              then (key('member', key('pos', $pos, $rules-doc)/@name, $main-input), 
                                    mf:fill($pos + 1, $length, $no-key))
                              else ($no-key[1], mf:fill($pos + 1, $length, $no-key[position() gt 1])))"/>
</xsl:function>

<xsl:template match="/">
  <xsl:sequence select="mf:fill(1, count($process), $no-key)"/>
</xsl:template>

</xsl:stylesheet>
<UI-defination>
   <class >
      <list_view >
         <members>
            <member col_span="1" name="code" displayName="Code"/>
            <member col_span="1" name="creationTS" displayName="CreationTS"/>
            <member col_span="1" name="creator" displayName="Creator"/>
            <member col_span="1" name="displayName" displayName="DisplayName"/>
            <member col_span="1" name="emailAddress" displayName="EmailAddress"/>
            <member col_span="1" name="id" displayName="Id"/>
         </members>
      </list_view>
   </class>
</UI-defination>

and the rules defining

<UI-defination>
    <class name="Role">
        <list_view multiselect="true">
            <members>
                <member name="displayName" sequence="2"/>
                <member name="code" sequence="4"/>
            </members>
            <exclude>
                <members>
                    <member name="id"/>
                    <member name="creator"/>
                </members>
            </exclude>
        </list_view>
    </class>
</UI-defination>
<member col_span="1" name="creationTS" displayName="CreationTS"/>
<member col_span="1" name="displayName" displayName="DisplayName"/>
<member col_span="1" name="emailAddress" displayName="EmailAddress"/>
<member col_span="1" name="code" displayName="Code"/>

Here is an adoption of the XSLT I posted to the XML input Michael posted:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:xs="http://www.w3.org/2001/XMLSchema"
  exclude-result-prefixes="xs mf"
  xmlns:mf="http://example.com/mf">

<!--
<xsl:param name="rules-uri" select="'test2014062704.xml'"/>
<xsl:variable name="rules-doc" select="doc($rules-uri)"/>
-->

<xsl:variable name="main-input" select="/"/>

<xsl:output indent="yes"/>

<xsl:key name="member" match="members/member" use="@id"/>

<xsl:key name="pos" match="members/member" use="xs:integer(@place)"/>

<xsl:variable name="process" select="members/member"/>

<xsl:variable name="no-key" select="members/member[not(@place)]"/>

<xsl:function name="mf:fill" as="element(member)*">
  <xsl:param name="pos" as="xs:integer"/>
  <xsl:param name="length" as="xs:integer"/>
  <xsl:param name="no-key" as="element(member)*"/>
  <xsl:sequence select="if ($pos gt $length)
                        then ()
                        else 
                          (if (key('pos', $pos, $main-input))
                              then (key('pos', $pos, $main-input), 
                                    mf:fill($pos + 1, $length, $no-key))
                              else ($no-key[1], mf:fill($pos + 1, $length, $no-key[position() gt 1])))"/>
</xsl:function>

<xsl:template match="/">
  <xsl:sequence select="mf:fill(1, count($process), $no-key)"/>
</xsl:template>

</xsl:stylesheet>

Then with Saxon 9.5 on the input

<members>
    <member id="1" place="9"/>
    <member id="2" place="2"/>
    <member id="3" place="5"/>
    <member id="4"/>
    <member id="5"/>
    <member id="6"/>
    <member id="7"/>
    <member id="8"/>
    <member id="9"/>
    <member id="10"/>
    <member id="11"/>
    <member id="12"/>
</members>
<member id="4"/>
<member id="2" place="2"/>
<member id="5"/>
<member id="6"/>
<member id="3" place="5"/>
<member id="7"/>
<member id="8"/>
<member id="9"/>
<member id="1" place="9"/>
<member id="10"/>
<member id="11"/>
<member id="12"/>

which is the same order it appears as the one produced by Michael's XSLT 1.0 code.

Thanks @Martin, but if i set sequence=3 of displayName and sequence=4 of code in rules.xml then your code shows same output instead I want in that scenario creationTS, emailAddress, displayName, code(in this order.)

I was kind of expecting this complication. :-) My answer has the same restriction as @Martin's as it outputs all explicitly sequenced entries first. Your second example would have been the better one for your question. I would suggest that you update your question accordingly.

I updated the question @MarcusRickert , Can u give it try ?

@BhushanPatil, I have changed the code but it does not give the result you say you want, as emailAddress is last and fourth of the four elements to be sorted so it ends up last after the sorting, even if we use the position() if no sequence exists in Rules.xml. So your requirement is currently not clear to me, you might need to explain it in more detail how elements that don't have a corresponding sequence are to be sorted.

@MartinHonnen Let me explain again, Very first requirement is that all the element from list_view/exclude/members should be removed. Then the elements which has sequence attr, they should be at that exact position. Then void position should get filled by the natural order of remaining element.(i.e. by the elements which don't have sequence attr., from default.xml)

Sorting in XSLT from two xml files - Stack Overflow

xml xslt xpath xslt-2.0
Rectangle 27 1

The following assumes you simply want to output the member elements, it uses a recursive function to construct the right sequence from the original elements, either using an element for which a position is defined in the rules.xml or filling the position with the next remaining element:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:xs="http://www.w3.org/2001/XMLSchema"
  exclude-result-prefixes="xs mf"
  xmlns:mf="http://example.com/mf">

<xsl:param name="rules-uri" select="'Rules.xml'"/>
<xsl:variable name="rules-doc" select="doc($rules-uri)"/>

<xsl:variable name="main-input" select="/"/>

<xsl:output indent="yes"/>

<xsl:key name="member" match="list_view/members/member" use="@name"/>

<xsl:key name="pos" match="list_view/members/member" use="xs:integer(@sequence)"/>

<xsl:variable name="exclude" select="key('member', $rules-doc//exclude/members/member/@name)"/>

<xsl:variable name="process" select="//list_view/members/member except $exclude"/>

<xsl:variable name="no-key" select="$process[not(key('member', @name, $rules-doc))]"/>

<xsl:function name="mf:fill" as="element(member)*">
  <xsl:param name="pos" as="xs:integer"/>
  <xsl:param name="length" as="xs:integer"/>
  <xsl:param name="no-key" as="element(member)*"/>
  <xsl:sequence select="if ($pos gt $length)
                        then ()
                        else 
                          (if (key('pos', $pos, $rules-doc))
                              then (key('member', key('pos', $pos, $rules-doc)/@name, $main-input), 
                                    mf:fill($pos + 1, $length, $no-key))
                              else ($no-key[1], mf:fill($pos + 1, $length, $no-key[position() gt 1])))"/>
</xsl:function>

<xsl:template match="/">
  <xsl:sequence select="mf:fill(1, count($process), $no-key)"/>
</xsl:template>

</xsl:stylesheet>
<UI-defination>
   <class >
      <list_view >
         <members>
            <member col_span="1" name="code" displayName="Code"/>
            <member col_span="1" name="creationTS" displayName="CreationTS"/>
            <member col_span="1" name="creator" displayName="Creator"/>
            <member col_span="1" name="displayName" displayName="DisplayName"/>
            <member col_span="1" name="emailAddress" displayName="EmailAddress"/>
            <member col_span="1" name="id" displayName="Id"/>
         </members>
      </list_view>
   </class>
</UI-defination>

and the rules defining

<UI-defination>
    <class name="Role">
        <list_view multiselect="true">
            <members>
                <member name="displayName" sequence="2"/>
                <member name="code" sequence="4"/>
            </members>
            <exclude>
                <members>
                    <member name="id"/>
                    <member name="creator"/>
                </members>
            </exclude>
        </list_view>
    </class>
</UI-defination>
<member col_span="1" name="creationTS" displayName="CreationTS"/>
<member col_span="1" name="displayName" displayName="DisplayName"/>
<member col_span="1" name="emailAddress" displayName="EmailAddress"/>
<member col_span="1" name="code" displayName="Code"/>

Here is an adoption of the XSLT I posted to the XML input Michael posted:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:xs="http://www.w3.org/2001/XMLSchema"
  exclude-result-prefixes="xs mf"
  xmlns:mf="http://example.com/mf">

<!--
<xsl:param name="rules-uri" select="'test2014062704.xml'"/>
<xsl:variable name="rules-doc" select="doc($rules-uri)"/>
-->

<xsl:variable name="main-input" select="/"/>

<xsl:output indent="yes"/>

<xsl:key name="member" match="members/member" use="@id"/>

<xsl:key name="pos" match="members/member" use="xs:integer(@place)"/>

<xsl:variable name="process" select="members/member"/>

<xsl:variable name="no-key" select="members/member[not(@place)]"/>

<xsl:function name="mf:fill" as="element(member)*">
  <xsl:param name="pos" as="xs:integer"/>
  <xsl:param name="length" as="xs:integer"/>
  <xsl:param name="no-key" as="element(member)*"/>
  <xsl:sequence select="if ($pos gt $length)
                        then ()
                        else 
                          (if (key('pos', $pos, $main-input))
                              then (key('pos', $pos, $main-input), 
                                    mf:fill($pos + 1, $length, $no-key))
                              else ($no-key[1], mf:fill($pos + 1, $length, $no-key[position() gt 1])))"/>
</xsl:function>

<xsl:template match="/">
  <xsl:sequence select="mf:fill(1, count($process), $no-key)"/>
</xsl:template>

</xsl:stylesheet>

Then with Saxon 9.5 on the input

<members>
    <member id="1" place="9"/>
    <member id="2" place="2"/>
    <member id="3" place="5"/>
    <member id="4"/>
    <member id="5"/>
    <member id="6"/>
    <member id="7"/>
    <member id="8"/>
    <member id="9"/>
    <member id="10"/>
    <member id="11"/>
    <member id="12"/>
</members>
<member id="4"/>
<member id="2" place="2"/>
<member id="5"/>
<member id="6"/>
<member id="3" place="5"/>
<member id="7"/>
<member id="8"/>
<member id="9"/>
<member id="1" place="9"/>
<member id="10"/>
<member id="11"/>
<member id="12"/>

which is the same order it appears as the one produced by Michael's XSLT 1.0 code.

Thanks @Martin, but if i set sequence=3 of displayName and sequence=4 of code in rules.xml then your code shows same output instead I want in that scenario creationTS, emailAddress, displayName, code(in this order.)

I was kind of expecting this complication. :-) My answer has the same restriction as @Martin's as it outputs all explicitly sequenced entries first. Your second example would have been the better one for your question. I would suggest that you update your question accordingly.

I updated the question @MarcusRickert , Can u give it try ?

@BhushanPatil, I have changed the code but it does not give the result you say you want, as emailAddress is last and fourth of the four elements to be sorted so it ends up last after the sorting, even if we use the position() if no sequence exists in Rules.xml. So your requirement is currently not clear to me, you might need to explain it in more detail how elements that don't have a corresponding sequence are to be sorted.

@MartinHonnen Let me explain again, Very first requirement is that all the element from list_view/exclude/members should be removed. Then the elements which has sequence attr, they should be at that exact position. Then void position should get filled by the natural order of remaining element.(i.e. by the elements which don't have sequence attr., from default.xml)

Sorting in XSLT from two xml files - Stack Overflow

xml xslt xpath xslt-2.0
Rectangle 27 1

Here is one approach. You define a key to group your items you are looking to remove. I think you are grouping by the @id attribute of the element, together with the @id attribute of the two parent nodes

<xsl:key 
   name="items" 
   match="*[@method != '']" use="concat(@id, '|', ../@id, '|', ../../@id)" />

Next, you could have a template to match your @method='create' items where there are two elements in the key, and the other item is a @method='delete'

<xsl:template match="*
   [@method = 'create']
   [count(key('items', concat(@id, '|', ../@id, '|', ../../@id))) = 2]
   [key('items', concat(@id, '|', ../@id, '|', ../../@id))[@method = 'delete']]" />

You would also need a template to match the other @method='delete' in a similar manner.

Here is the full XSLT

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
   <xsl:output method="xml" indent="yes"/>

   <xsl:key name="items" match="*[@method != '']" use="concat(@id, '|', ../@id, '|', ../../@id)" />

   <xsl:template match="*[@method = 'create'][count(key('items', concat(@id, '|', ../@id, '|', ../../@id))) = 2][key('items', concat(@id, '|', ../@id, '|', ../../@id))[@method = 'delete']]" />
   <xsl:template match="*[@method = 'delete'][count(key('items', concat(@id, '|', ../@id, '|', ../../@id))) = 2][key('items', concat(@id, '|', ../@id, '|', ../../@id))[@method = 'create']]" />

   <xsl:template match="@*|node()" name="identity">
      <xsl:copy>
         <xsl:apply-templates select="@*|node()"/>
      </xsl:copy>
   </xsl:template>
</xsl:stylesheet>
<root>
   <sector>
      <nodeA id="a">
         <section id="i"/>
      </nodeA>
      <nodeA id="b">
         <cell id="ii"/>
         <cell id="ii"/>
      </nodeA>
      <nodeB id="i">
         <cell id="ii">
            <item3 id="1" method="create">
               <child>b</child>
            </item3>
         </cell>
         <cell id="ii">
            <item3 id="1" method="delete"/>
            <item3 id="1" method="create">
               <otherchild>a</otherchild>
            </item3>
         </cell>
      </nodeB>
   </sector>
</root>

How to do this xml elimination based on node attribute positions using...

xml xslt
Rectangle 27 1

Well in general HTML is not XML and you won't be able to use document('file.html') sucessfully. But in your case it seems that operation works but you failed to ensure your root element is copied, so you end up with two top level elements in the result document which is then not XML as there needs to be a single root element. So add

<xsl:template match="/*">
  <xsl:copy>
    <xsl:apply-templates/>
  </xsl:copy>
</xsl:template>

in your XSLT and the result will be a well-formed XML document with a single root element.

That rather cryptic error message basically tells you that the markup following the first result element does not match the Misc production in the XML specification which only allows comments and/or processing instructions following the single allowed root element.

Thank you so much! Everything works just fine now! I didn't really realize i was missing the root element and that it's mandatory. Again, thank you, i learned a lot. =)

Concatenate two xml/html Files with XSLT - Stack Overflow

html xml xslt
Rectangle 27 116

Using one of the most fundamental XSLT design patterns: "Overriding the identity transformation" one will just write the following:

Do note how the second template overrides the identity (1st) template only for elements named "Element" that have an attribute "fruit" with value "apple" and attribute "animal" with value "cat". This template has empty body, which means that the matched element is simply ignored (nothing is produced when it is matched).

When this transformation is applied on the following source XML document:

the wanted result is produced:

More code snippets of using and overriding the identity template can be found here.

Despite me not even asking the right question, you've answered exactly what I should have asked! :)

Why don't you mark this post as the correct answer then? Then it would disappear form the list of unanswered problems.

/bookstore/book[position() = 1 or position() = 3]/@*
/*/book[position() = 1 or position() = 3]/@*
/*/book[position() = (1,3)]/@*

How to remove elements from xml using xslt with stylesheet and xsltpro...

xml xslt
Rectangle 27 1

Let me suggest the following approach:

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:wix="http://schemas.microsoft.com/wix/2006/wi"
xmlns:exsl="http://exslt.org/common"
extension-element-prefixes="exsl">
<xsl:output method="xml" version="1.0" encoding="utf-8" indent="yes"/>
<xsl:strip-space elements="*"/>

<xsl:param name="parts" select="document('parts.xml')"/>

<xsl:variable name="x-paths">
    <xsl:call-template name="tokenize">
        <xsl:with-param name="text" select="normalize-space($parts//Fig[@Directory='OutputFiles'])"/>
        <xsl:with-param name="delimiter" select="' '"/>
    </xsl:call-template>
</xsl:variable>

<xsl:variable name="x-steps">
    <xsl:for-each select="exsl:node-set($x-paths)/token">
        <xsl:call-template name="tokenize">
            <xsl:with-param name="text" select="."/>
        </xsl:call-template>
    </xsl:for-each>
</xsl:variable>

<xsl:variable name="x-ids">
    <xsl:for-each select="/wix:Wix/wix:Fragment/wix:DirectoryRef/wix:Component">
        <xsl:variable name="steps">
            <xsl:call-template name="tokenize">
                <xsl:with-param name="text" select="wix:File/@Source"/>
                <xsl:with-param name="delimiter" select="'\'"/>
            </xsl:call-template>
        </xsl:variable>
        <xsl:if test="exsl:node-set($steps)/token = exsl:node-set($x-steps)/token">
            <id>
                <xsl:value-of select="@Id"/>
            </id>
        </xsl:if>
    </xsl:for-each>
</xsl:variable>

<!-- identity transform -->
<xsl:template match="@*|node()">
    <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
</xsl:template>

<xsl:template match="wix:Component | wix:ComponentRef">
    <xsl:if test="not(@Id = exsl:node-set($x-ids)/id)">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:if>
</xsl:template>

<xsl:template name="tokenize">
    <xsl:param name="text"/>
    <xsl:param name="delimiter" select="'/'"/>
        <xsl:variable name="token" select="substring-before(concat($text, $delimiter), $delimiter)" />
        <xsl:if test="$token">
            <token>
                <xsl:value-of select="$token"/>
            </token>
        </xsl:if>
        <xsl:if test="contains($text, $delimiter)">
            <!-- recursive call -->
            <xsl:call-template name="tokenize">
                <xsl:with-param name="text" select="substring-after($text, $delimiter)"/>
                <xsl:with-param name="delimiter" select="$delimiter"/>
            </xsl:call-template>
        </xsl:if>
</xsl:template>

</xsl:stylesheet>
<?xml version="1.0" encoding="utf-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
   <Fragment>
      <DirectoryRef Id="INSTALLDIRECTORY">
         <Component Id="cmp2A1630B8E0E70C310FC91CD5DADB5A43" Guid="*">
            <File Id="filF5C36F42ADA8B3DD927354B5AB666898" KeyPath="yes" Source="$(env.srcDir)\thisWillStay.txt"/>
         </Component>
         <Directory Id="dir2A411B40F7C80649B57155F53DD7D136" Name="ThisWillStay">
            <Component Id="cmpE7DF6F3C9BE17355EA10D49649C4957A" Guid="*">
               <File Id="fil908CF12B8DD2E95A77D7611874EC3892" KeyPath="yes" Source="$(env.srcDir)\ThisWillStay\file1.txt"/>
            </Component>
         </Directory>
      </DirectoryRef>
   </Fragment>
   <Fragment>
      <ComponentGroup Id="DeliveredFiles">
         <ComponentRef Id="cmp2A1630B8E0E70C310FC91CD5DADB5A43"/>
         <ComponentRef Id="cmpE7DF6F3C9BE17355EA10D49649C4957A"/>
      </ComponentGroup>
   </Fragment>
</Wix>

Wow, thanks for the help! This almost works. It seems to work perfectly for the first and last item in the Fig list, but it doesn't remove any of the files that are in the middle. Also, I initially got an error saying: Namespace 'http://exslt.org/common' does not contain any functions, so I replaced it with the namespace xmlns:msxsl="urn:schemas-microsoft-com:xslt" and xmlns:user="http://www.contoso.com", replacing all of the exsl: prefixes with msxsl: prefixes.

@AndrewDiNunzio I am not sure what you mean by "files that are in the middle". I have posted my result. How does it differ from yours?

The <Fig Directory="OutputFiles"> contains foo/bar/file1.txt, foo/bar/file2.exe, and foo/bar/Some.File.dll. But the code you provided successfully removes nodes related to file1.txt and Some.File.dll (the first and last in the list), but the node related to "file2.exe" stays behind. I'm sorry, I should have provided multiple entries in my sample input. I'll edit my original question and add it to the sample input. Thanks for bearing with me

Ran a few tests, and it seems to work perfectly now! Thank you so much! (marking this as accepted, but I'll be sure to upvote it once I get the necessary reputation points)

wix - Using XSLT 1.0 to remove elements (WXS components/files/etc) bas...

xslt wix xslt-1.0 msxsl
Rectangle 27 1

<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:output method="xml" encoding="UTF-8" indent="yes" />
    <xsl:strip-space elements="*" />

    <xsl:template match="FormData">
        <xsl:copy>
            <xsl:copy-of select="@*" />
            <ItemGroupData>
                <xsl:copy-of select="ItemGroupData[1]/@*" />
                <xsl:copy-of select="*/ItemData" />
            </ItemGroupData>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
</xsl:transform>

There are two templates here. The second one, commonly called the identity template, applies to any node for which there is no more specific template defined. All it does is copy the input as-is. This template does the bulk of the work, copying most of the input document unchanged.

The first template matches only one specific element, namely <FormData>. This template copies the <FormData> itself and its attributes, then creates a new <ItemGroupData>, copies the attributes of the first <ItemGroupData> in the current <FormData> and finally all <ItemData> elements from one level deeper.

The output is:

<ClinicalData xmlns:OpenClinica="OpenClinica" StudyOID="S_ABCD1" MetaDataVersionOID="v1.0.0">
   <SubjectData SubjectKey="SS_ABCD1068" OpenClinica:StudySubjectID="1068">
      <StudyEventData StudyEventOID="SE_ABVISIT1" StudyEventRepeatKey="1">
         <FormData FormOID="F_ABCDEKGINTER_VER10">
            <ItemGroupData ItemGroupOID="IG_ABCDE_UNGROUPED_366" TransactionType="Insert">
               <ItemData ItemOID="I_ABCDE_AUTO_ID_4698" Value="1926"/>
               <ItemData ItemOID="I_ABCDE_EKGCDRID" Value="453"/>
               <ItemData ItemOID="I_ABCDE_EKGDATE" Value="2010-02-25"/>
               <ItemData ItemOID="I_ABCDE_EKGTTRID" Value="616"/>
               <ItemData ItemOID="I_ABCDE_EKG01" Value="1"/>
            </ItemGroupData>
         </FormData>
      </StudyEventData>
   </SubjectData>
   <SubjectData SubjectKey="SS_ABCD1669" OpenClinica:StudySubjectID="1669">
      <StudyEventData StudyEventOID="SE_ABVISIT1" StudyEventRepeatKey="1">
         <FormData FormOID="F_ABCDEKGINTER_VER10">
            <ItemGroupData ItemGroupOID="IG_ABCDE_UNGROUPED_366" TransactionType="Insert">
               <ItemData ItemOID="I_ABCDE_AUTO_ID_4698" Value="1796"/>
               <ItemData ItemOID="I_ABCDE_EKG02" Value="1"/>
               <ItemData ItemOID="I_ABCDE_EKGCDRID" Value="453"/>
               <ItemData ItemOID="I_ABCDE_EKGDATE" Value="2009-12-21"/>
               <ItemData ItemOID="I_ABCDE_EKGTTRID" Value="616"/>
               <ItemData ItemOID="I_ABCDE_EKG01" Value="1"/>
               <ItemData ItemOID="I_ABCDE_EKG03" Value="1"/>
            </ItemGroupData>
         </FormData>
      </StudyEventData>
   </SubjectData>
</ClinicalData>
OpenClinica

Sign up for our newsletter and get our top new questions delivered to your inbox (see an example).

xslt - How to remove or eliminate duplicate XML element tags leaving o...

xml xslt
Rectangle 27 1

If two <NodeE> elements are considered duplicates only if they have the same parent, this is probably the simplest solution:

<?xml version="1.0"?>

<NodeA NodeAattr="123">

  <NodeB NodeBattr="456"></NodeB>

  <NodeC>
    <NodeD Name="ValueD">
      <NodeE Name="ValueABC">
        <NodeF Value="0"></NodeF>
      </NodeE>
      <NodeE Name="ValueABC">
        <NodeF Value="0"></NodeF>
      </NodeE>
    </NodeD>
    <!-- Added another <NodeD> element for demonstration -->
    <NodeD>
      <NodeE Name="ValueABC">
        <NodeF Value="0"></NodeF>
      </NodeE>
      <NodeE Name="ValueDEF">
        <NodeF Value="0"></NodeF>
      </NodeE>
    </NodeD>
  </NodeC>
</NodeA>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" version="1.0" encoding="utf-8" indent="yes"/>
  <xsl:strip-space elements="*"/>

  <!--
  Identity transform: copy elements and attributes from input file as is
  -->
  <xsl:template match="node() | @*">
    <xsl:copy>
      <xsl:apply-templates select="node() | @*"/>
    </xsl:copy>
  </xsl:template>

  <!--
  Drop <NodeE> elements with a preceding <NodeE> sibling that has the same
  @Name attribute value as the current element
  -->
  <xsl:template
    match="NodeE[preceding-sibling::NodeE[@Name = current()/@Name]]"/>

</xsl:stylesheet>

On the other hand, if <NodeE> elements should be considered duplicates across the whole document, you can use Muenchian grouping:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" version="1.0" encoding="utf-8" indent="yes"/>
  <xsl:strip-space elements="*"/>

  <xsl:key name="kNode" match="NodeE" use="@Name"/>

  <!--
  Identity transform: copy elements and attributes from input file as is
  -->
  <xsl:template match="node() | @*">
    <xsl:copy>
      <xsl:apply-templates select="node() | @*"/>
    </xsl:copy>
  </xsl:template>

  <!--
  Use Muenchian grouping to apply unique NodeE elements.
  See http://www.jenitennison.com/xslt/grouping/muenchian.html
  -->
  <xsl:template match="NodeE[generate-id() = 
                       generate-id(key('kNode', @Name)[1])]">
    <xsl:copy>
      <xsl:apply-templates select="node() | @*"/>
    </xsl:copy>
  </xsl:template>

  <!-- Drop other <NodeE> elements -->
  <xsl:template match="NodeE"/>

</xsl:stylesheet>
<?xml version="1.0" encoding="utf-8"?>
<NodeA NodeAattr="123">
  <NodeB NodeBattr="456"/>
  <NodeC>
    <NodeD Name="ValueD">
      <NodeE Name="ValueABC">
        <NodeF Value="0"/>
      </NodeE>
    </NodeD>
    <NodeD>
      <NodeE Name="ValueDEF">
        <NodeF Value="0"/>
      </NodeE>
    </NodeD>
  </NodeC>
</NodeA>

@ Eero It works like a charm. Thanks a ton. But I have one more question in mind. For instance, if I want to remove only the duplicate node whose 'Name' attribute value is "ValueABC", how this will be restructured? I dont want to touch the other nodes whose 'Name' attributes' values are "ValueDEF", "ValueGHJ"

For stylesheet #1, the change is pretty simple, just add a predicate to narrow down the node set: <xsl:template match="NodeE[@Name = 'ValueABC'][preceding-sibling::NodeE[@Name = current()/@Name]]"/>. For #2, you could do something like this. There might be a simpler solution for #2, but that's what popped into my mind first.

Thanks a lot for the favor..

On a similar note, could you provide me with your comments on this one as well ? stackoverflow.com/questions/16020026/

xml - XSL - remove the duplicate node but keep the original - Stack Ov...

xml xslt xslt-1.0 duplicate-removal
Rectangle 27 2

Your input document was so full of formation errors, I've had to take the risk of guessing your intentions. Please see the transform solution below. I deliberately did not include the insertion of the table elements around your comment "ADD TABLE/TR/TD TAG", as this section seemed so nutty that any solution that I provided for you here would likely be a wrong interpretation of your required rules of transformation.

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:xhtml="http://www.w3.org/1999/xhtml"
 xmlns="http://www.w3.org/1999/xhtml"
 exclude-result-prefixes="xhtml">
<xsl:output method="xml" indent="yes" encoding="UTF-8"/>
<xsl:strip-space elements="*" />

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

<xsl:template match="xhtml:body">
  <element add="xyz" id="23" />
  <element add="xyz" id="24" />
 <body onLoad="ada" bgcolor="pink">
  <xsl:apply-templates select="@*|node()"/>
  </body>
</xsl:template>

<xsl:template match="xhtml:element1[@name='abc']/@src">
  <xsl:attribute name="src">xyz.jpg</xsl:attribute>  
</xsl:template>

<xsl:template match="xhtml:input[@id='1']">
  <form name="form">
   <xsl:copy>
    <xsl:apply-templates select="@*|node()"/>
   </xsl:copy>
   <xsl:apply-templates select="following-sibling::xhtml:div[1]" mode="inside-form"/> 
  </form>
</xsl:template>

<xsl:template match="xhtml:div[ preceding-sibling::xhtml:*[1]
   /self::xhtml:input[@id='1']]"/>

<xsl:template match="xhtml:div" mode="inside-form">
 <xsl:copy>
  <xsl:apply-templates select="@*|node()"/>
 </xsl:copy>
 <input type="submit" value="Done"/> 
</xsl:template>

</xsl:stylesheet>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
 <meta http-equiv="Content-type" content="text/html;  charset=utf-8" />
</head>
<body>
 <div id="o">
  <div id="nd">
   <p>1</p>
  </div>
  <div class="TF" id="id12">
   <element1 name="abc" src="abc.jpg"/>
   <input type="radio" id="1" event="xyz"/>
   <div class="q">
    <br/>
    <div id="ta3" class="block">
     <span style="a">ABC</span>
    </div>
    <br/>T <input/> F <input/>
    <div id="sf">
     <div id="ta3">
     </div>
    </div>
   </div>
  </div>
 </div>
</body>
</html>
<?xml version="1.0" encoding="utf-8"?>
<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <meta http-equiv="Content-type" content="text/html;  charset=utf-8" />
  </head>
  <element add="xyz" id="23" />
  <element add="xyz" id="24" />
  <body onLoad="ada" bgcolor="pink">
    <div id="o">
      <div id="nd">
        <p>1</p>
      </div>
      <div class="TF" id="id12">
        <element1 name="abc" src="xyz.jpg" />
        <form name="form">
          <input type="radio" id="1" event="xyz" />
          <div class="q">
            <br />
            <div id="ta3" class="block">
              <span style="a">ABC</span>
            </div>
            <br />T <input /> F <input /><div id="sf"><div id="ta3" /></div></div>
          <input type="submit" value="Done" />
        </form>
      </div>
    </div>
  </body>
</html>

@SeanBDurkin Thanks a lot for the reply. I'll do it in the way you mentioned. Thanks again.

Thanks a lot it works perfectly. Now I can try some modifications. :)

I have a question. Like in the above source XHTML, there is one- <element1 name="abc" src="abc.jpg"/>, while in my complete source file I have one more along with that like <element1 name="abc" src="pqr.jpg"/> and one inside 'head' tag like <element1 name="abc" src="lmn.jpg"/>, So when I apply the above XSLT then it changes the value of source everywhere and makes it xyz.jpg while I have to change only where src="abc.jpg". So can you please tell me that how can I achieve that? Thanking you!

I tried something like this- <xsl:template match="xhtml:element1[@src='abc.jpg']"> But its not working out, it removes the entire element1 tag where src="abc.jpg"

Hi Rahul. Please post your question as another question. I and others will look at it. For best results, provide a sample input, expected output, XSLT version (1.0 or 2.0) and the rules of transformation. Also make sure that xml listings are well-formed and free of error. I am looking forward to seeing your new question.

XML to XML with XSLT- Add, Remove, Modify Elements and Attributes - St...

xml xslt xhtml