473,545 Members | 1,479 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

XSLT compare attributes of XML nodes

22 New Member
Hi all,
I am trying to merge 2 XML files that first of all i need to compare nodes of both files according to 2 attributes in the nodes. If those 3 attributes are equal, i need to replace the existing node with the new one. For example first xml file will be like;

Expand|Select|Wrap|Line Numbers
  1. <Root>
  2.           <Node Id ="1" FormId="form1" Value="value1"/>
  3.           <Node Id ="2" FormId="form1" Value="value2"/>
  4.           <Node Id ="3" FormId="form1" Value="value3"/>
  5. </Root>
and second xml file will be like;

Expand|Select|Wrap|Line Numbers
  1. <Root>
  2.           <Node Id ="1" FormId="form1" Value="NewValue1"/>
  3.           <Node Id ="2" FormId="form1" Value="NewValue2"/>
  4.           <Node Id ="4" FormId="form1" Value="NewValue4"/>
  5. </Root>
and when i merged these 2 files result should be;

Expand|Select|Wrap|Line Numbers
  1. <Root>
  2.           <Node Id ="1" FormId="form1" Value="NewValue1"/>
  3.           <Node Id ="2" FormId="form1" Value="NewValue2"/>
  4.           <Node Id ="3" FormId="form1" Value="value3"/>
  5.           <Node Id ="4" FormId="form1" Value="NewValue4"/>
  6. </Root>
In those files, i compare the nodes of the second file with the nodes of the first file according to "Id" and "FormId" attributes. If those attributes are equal, that node in the first file will be replaced with the node in the second file. If they are not equal, current node in the second file will be written in the first file. What i have done so far is merging two xml files by comparing the distinct nodes according to all attributes in the nodes. But i couldn't manage only comparing nodes according to "Id" and "FormId" attributes. I am using that XSLT code to compare the equalty of the nodes and it works fine.

Expand|Select|Wrap|Line Numbers
  1. <xsl:for-each select="$node1/@*">       
  2.             <xsl:if test="not($node2/@* [local-name()=local-name(current()) and namespace-uri()=namespace-uri(current()) and .=current()])">.</xsl:if>
  3. </xsl:for-each>
When i changed that code only to compare according to those 2 attributes it doesn't work.

Expand|Select|Wrap|Line Numbers
  1. <xsl:for-each select="$node1/@*">
  2.             <xsl:if test="not($node2/@* [@Id = current()/@Id and @FormId = current()/@FormId])">.</xsl:if>
  3. </xsl:for-each>
Any help would be appreciated.
Nov 17 '08 #1
12 18252
Dormilich
8,658 Recognized Expert Moderator Expert
you put in one attribute node too many. use $node2 instead of $node2/@*. 1)

a more elagant way would be without the if clause
Expand|Select|Wrap|Line Numbers
  1. <xsl:for-each select="$node1[@Id != $node2/@Id][@FormId != $node2/@FormId]">
  2. // code goes here for every unique $node1
  3. </xsl:for-each>
regards

1)
Expand|Select|Wrap|Line Numbers
  1. // your first condition
  2. $node2/@* [@Id = current()/@Id]
  3. // resolves to
  4. $node2/@*/@Id = $node1/@*/@Id
  5. // which returns true (both are empty/invalid) ...
Nov 17 '08 #2
blackirish
22 New Member
Dormilich, thanks for your reply,
I tried what you recommended like the following;

Expand|Select|Wrap|Line Numbers
  1. <xsl:for-each select="$node1[@Id != $node2/@Id][@FormId != $node2/@FormId]">
  2.             <xsl:if test="not($node2/@*/@Id = $node1/@*/@Id and $node2/@*/@FormId = $node1/@*/@FormId)">.</xsl:if>
  3. </xsl:for-each>
But it still gives the same output. What am i doing wrong?
Nov 17 '08 #3
Dormilich
8,658 Recognized Expert Moderator Expert
you misunderstood. my code doesn't require <xsl:if>. the for-each loop should select all unique elements of $node1 (so that you can copy them).

regards

Expand|Select|Wrap|Line Numbers
  1. <xsl:if test="not($node2/@*/@Id = $node1/@*/@Id and $node2/@*/@FormId = $node1/@*/@FormId)">.</xsl:if>
will always fail since there are no elements who fulfill this condition.

Explanation:
Expand|Select|Wrap|Line Numbers
  1. $node2/@*/@Id -> empty
  2. $node1/@*/@Id -> empty
  3. empty = empty -> true
  4. not(true) -> false -> if statement skipped
Nov 17 '08 #4
blackirish
22 New Member
Sorry for misunderstandin g. My XSLT code has two parts. First part compares the nodes and second part copies the nodes according to the results of comparation. When comparing if required attributes are equal, i need to get a "=" and after that update the node. If attributes are not equal, i need to get a "!" and then copy the node from second file to the first file. Below is the comparation part of the code.

Expand|Select|Wrap|Line Numbers
  1. <!-- 
  2.  Comparing single nodes: 
  3.      if $node1 and $node2 are equivalent then the template creates a 
  4.      text node "=" otherwise a text node "!" -->
  5.      <xsl:template name="m:compare-nodes">
  6.       <xsl:param name="node1" />
  7.       <xsl:param name="node2" />
  8.        <xsl:variable name="type1">
  9.         <xsl:apply-templates mode="m:detect-type" select="$node1" />
  10.       </xsl:variable>
  11.        <xsl:variable name="type2">
  12.         <xsl:apply-templates mode="m:detect-type" select="$node2" />
  13.       </xsl:variable>
  14.        <xsl:choose>
  15.          <!--  Are $node1 and $node2 element nodes with the same name? -->
  16.          <xsl:when test="$type1='element' and $type2='element' and local-name($node1)=local-name($node2) and namespace-uri($node1)=namespace-uri($node2) and name($node1)!=$dontmerge and name($node2)!=$dontmerge">
  17.            <!--  Comparing the attributes -->
  18.            <xsl:variable name="diff-att">
  19.              <!--  same number ... -->
  20.             <xsl:if test="count($node1/@*)!=count($node2/@*)">.</xsl:if>
  21.              <!--  ... and same name/content -->
  22.              <xsl:for-each select="$node1/@*">
  23.              <!--<xsl:for-each select="$node1/Caption">-->
  24.                <xsl:value-of select="@Id" />
  25.                <xsl:value-of select="@FormId" />
  26.                <xsl:value-of select="@LangId" />
  27.                <!--<xsl:if test="not($node2/Caption/Id/FormId/LangId [local-name()=local-name(current()) and namespace-uri()=namespace-uri(current()) and .=current()])">.</xsl:if>-->
  28.                <xsl:if test="not($node2/@* [local-name()=local-name(current()) and namespace-uri()=namespace-uri(current()) and .=current()])">.</xsl:if>
  29.             </xsl:for-each>
  30.           </xsl:variable>
  31.            <xsl:choose>
  32.             <xsl:when test="string-length($diff-att)!=0">!</xsl:when>
  33.             <xsl:otherwise>=</xsl:otherwise>
  34.           </xsl:choose>
  35.         </xsl:when>
  36.          <!--  Other nodes: test for the same type and content -->
  37.         <xsl:when test="$type1!='element' and $type1=$type2 and name($node1)=name($node2) and ($node1=$node2 or ($normalize='yes' and normalize-space($node1)= normalize-space($node2)))">=</xsl:when>
  38.          <!--  Otherwise: different node types or different name/content -->
  39.         <xsl:otherwise>!</xsl:otherwise>
  40.       </xsl:choose>
  41.     </xsl:template>
Sorry i don't know much about XSLT so i have difficulty in solving the problem.

Regards,
Nov 17 '08 #5
blackirish
22 New Member
Anybody knows how to fix that??
Nov 17 '08 #6
Dormilich
8,658 Recognized Expert Moderator Expert
if you just (well...) want to merge two files, why making it by the means of a comparison string? Isn't that complicated (well, it looks so...)?

As I (hopefully) understand you right you want to merge two xml files omitting duplicate nodes (regarding the attributes) from the first xml. Do you need "!" and "=" in the output too?

I'd do a straightforward merging.

the idea is to copy all nodes from xml no.2 and add all nodes from xml no.1 that are not present in xml no.2.

like (sketch)
Expand|Select|Wrap|Line Numbers
  1. // select mergable nodes
  2. <xsl:variable name="node1" select="//*[self::name() != $dontmerge]"/>
  3. //... there may be more conditions depending on the xml
  4.  
  5. <xsl:template match="/">
  6.   <xsl:apply-templates/>
  7. </xsl:template>
  8.  
  9. // add xml no.2
  10. <xsl:template match="$node2">
  11.   <xsl:copy-of select="."/> // or whatever value you need
  12. </xsl:template>
  13.  
  14. // add xml no.1 using conditions
  15. <xsl:template match="$node1[@Id != $node2/@Id][@FormId != $node2/@FormId]">
  16.   <xsl:copy-of select="."/> // or whatever value you need
  17. </xsl:template>
this idea should at least work for your example....

regards
Nov 17 '08 #7
blackirish
22 New Member
Thanks again for your reply. In your code i can only insert the nodes which doesn't exist in the file1. But i also want to replace the nodes having the same "Id" and "FormId" attribute values. For ex. if i have a line in file1 like;

Expand|Select|Wrap|Line Numbers
  1. <Node Id="1" FormId="form1" Values="value1"> 
and a line in file2 like;

Expand|Select|Wrap|Line Numbers
  1. <Node Id="1" FormId="form1" Values="new Value"> 
which both nodes have same "Id" and "FormId" attribute values("1" and "form1") and corresponding output will be;

Expand|Select|Wrap|Line Numbers
  1. <Node Id="1" FormId="form1" Values="new Value"> 
that first node will be replaced with second node. So i have two options according to what i get from the comparation("!" or "="). If result is "!" i will insert the node from the file2 to file1, and if result is "=" i will replace the node(as in the example above). So is it possible to modify the code i give to get a result "!" or "=" according to the values of "Id" and "FormId" attributes.
Hope it is obvious to understand.

Regards
Nov 17 '08 #8
jkmyoung
2,057 Recognized Expert Top Contributor
Sorry if I'm misinterpreting (my mind isn't working that well yet today).
Are you sorting based on id? Is it possible to have the same id, but different FormId?

Would have suggested a 1-liner:
<xsl:copy-of select="$node1[not ($node2[@Id = current()/@Id])] | $node2"/>

or if order matters, change to a for-each:
Expand|Select|Wrap|Line Numbers
  1. <xsl:for-each select="$node1[not ($node2[@Id = current()/@Id])] | $node2">
  2.   <xsl:sort select="@Id" order="ascending"/>
  3.   <xsl:copy-of select="."/>
  4. </xsl:for-each>
  5.  
Otherwise, I agree with Dormilich about the xpath being wrong. (attributes don't have children attributes)

---
I think we're going about the same problem 2 different ways.
If we're going to 'update' the old node with new values, why not just copy the new node?
Nov 17 '08 #9
blackirish
22 New Member
Of course it may have the same Id and different FormId and i can already copy the node in the merge part. And in the xml files attributes don't have child attributes(i know it is impossible). Just each node has attributes ("Id", "FormId", "Values"). Merging part of the XSLT file can copy the nodes correctly. But when i comparing the nodes("m:compar e-nodes" template i sent in one of the messages above) i always get a "!" that shows nodes are not equal(eventhoug h "Id" and "FormId" attribute values are equal). I only want to get the correct output ("!" or "=") from the compare template. By the way i don't need to sort the nodes. Here i need to modify the above "m:compare-nodes" template.

Regards
Nov 17 '08 #10

Sign in to post your reply or Sign up for a free account.

Similar topics

9
2879
by: Iain | last post by:
I want to create an XML configuration file which might look like <REGION Name="Europe" WingDing="Blue"> <COUNTRY Name="UK" WingDing="white"> <TOWN Name="London" WingDing="Orange" /> </COUNTRY> </REGION> <REGION Name="NorthAmerica" WingDing="Yellow"> <COUNTRY Name="Canada"> <TOWN Name="Quebec" WingDing="Brown" />
5
9533
by: inquirydog | last post by:
Hi- Does anyone know a way to compare whether two nodes contain the same information in xslt (the name, attributes, and all content recursivly should be the same. I am interested in the case where node ordering matters, and also the case where it doesn't, but perhaps that is an advanced topic). Ideally the method should be available to...
2
1831
by: Jon Martin Solaas | last post by:
Hi, I have a general document somewhat like this: -------------------------------------- <root> <level1> <level2> <interestingstuff number="2"/> <interestingstuff number="3"/> <interestingstuff number="1"/>
3
9903
by: Stephan Brunner | last post by:
Hi I have created two flavors of an XSLT stylesheet to transform all attributes of an XML document to elements: They both work as expected with MSXML and XMLSPY but throw an exception ========================= <?xml version="1.0" encoding="iso-8859-1"?> <xsl:stylesheet version="1.0"
3
1739
by: Alex | last post by:
I stumbled upon this while developing a custom XPathNavigator. It appears that copy action for attributes is broken in the .net framework XSLT processor. The intent was to just copy the entities and attributes from the source XML into the output using simple "identity" like XSLT: <xsl:stylesheet...
3
3073
by: Ian Roddis | last post by:
Hello, I want to embed SQL type queries within an XML data record. The XML looks something like this: <DISPLAYPAGE> <FIELD NAME="SERVER" TYPE="DROPDOWN"> <OPTION>1<OPTION> <OPTION>2<OPTION> <OPTION>3<OPTION> </FIELD>
1
1258
by: Foxpointe | last post by:
Given some arbitrary XHTML, I'd like to obtain a 'simplified' XHTML result which strips out a large subset of standard elements and attributes - but not all. The main things I would like to accomplish: 1) Provide a list of elements/attributes to be stripped (i.e. everything else should be passed through) or those that should be passed...
1
1398
by: byquestion | last post by:
Hi there xslt gurus, i am kinda new to xslt and having difficulty to implement my some iterations. i need to recreate an xml file by using xslt. here is the sample xml file(input for xslt) <Flights> <Flight> <FlightLeg > <BookingClassCodeList> <BookingCode Value="C" /> <BookingCode Value="Y" /> ...
0
7651
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers, it seems that the internal comparison operator "<=>" tries to promote arguments from unsigned to signed. This is as boiled down as I can make it. ...
0
7802
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven tapestry of website design and digital marketing. It's not merely about having a website; it's about crafting an immersive digital experience that...
0
7746
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each protocol has its own unique characteristics and advantages, but as a user who is planning to build a smart home system, I am a bit confused by the...
0
5962
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing, and deployment—without human intervention. Imagine an AI that can take a project description, break it down, write the code, debug it, and then...
1
5320
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new presenter, Adolph Dupré who will be discussing some powerful techniques for using class modules. He will explain when you may want to use classes...
0
4941
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and then checking html paragraph one by one. At the time of converting from word file to html my equations which are in the word document file was convert...
0
3443
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols. I succeeded, with both firewalls in...
1
1010
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.
0
693
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence can significantly impact your brand's success. BSMN Consultancy, a leader in Website Development in Toronto offers valuable insights into creating...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.