Link to home
Start Free TrialLog in
Avatar of psilli1
psilli1

asked on

Two xml Documents to One!

Hi,

I have an XML document that links to two further XML documents, I need to take the first and run a calculation from a value off the second, and from this produce a third file.

I am iterating through the first using an for-each loop, after opening the document with the document command, writing ourput as I go.

When I come to a point where the identifiying variable is, I am trying to then go into the second XML document to retrieve the data I need, this is where I am struggling.

I am under the impression that I have moved down the tree to the point in XML file 1, then I must go up the tree to the first XML document that links the two files to then enter the second linked document containing the data.

I can't see how I can get data betwwen the two documents.

If anyone understands this can they plz help!

Thanks in advance.
Avatar of b1xml2
b1xml2
Flag of Australia image

you can do this via the xslt document function. What parser are you using? You would also have to probably use the node-set function as well.

Post your XML documents (small data sets please) and your expected XML output and also, your XSLT document (i need to know the logic you are using) and we are cooking!
By the way, the best approach is to use XSLT to do the transform.

You could use the appendChild() to append the two documents into the main tree and then run the transform. Trying to do what you are doing using DOM methods alone is a nightmare.
Avatar of psilli1
psilli1

ASKER

Hi,

I am using Saxon parser, I seem to have got around the problem but I am not sure if it is a good way or not.  I have created two parameters at the top of the XSLT, one for each of the filenames, now in the main templates of the XSLT i can simply reference which document I need.  It seems to work ok at the moment.

I am very interested though in how the node-set function is used.  I am assuming that it can be used to create a resultant node-set, which can then be parsed to obtain the data.

This is the main xml document, that links the further two together!
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE Update SYSTEM "blah.DTD">
<?xml-stylesheet href="blah.xsl" type="text/xsl"?>
<blah>
     <el1 filename="blah.xml"/>
     <el2 filename="blahblah.xml"/>
</blah>

One Data File
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE NFLDivisions SYSTEM "onedata.dtd">
<main>
     <area>
          <Name>North</Name>
          <Team>
               <TeamName>Manchester United</TeamName>
               <League>
                    <Goals>
                         <For>100</For>
                         <Against>94</Against>
                    </Goals>
                    <WLTBreakdown Performance="home">
                         <Won>1</Won>
                         <Lost>0</Lost>
                         <Tied>0</Tied>
                    </WLTBreakdown>
                    <WLTBreakdown Performance="away">
                         <Won>1</Won>
                         <Lost>0</Lost>
                         <Tied>0</Tied>
                    </WLTBreakdown>

.......etc.......


The second xml document contains games.
<Score>
  <Game>
    <Home>
      <Team>Manchester Utd</Team>
      <Result>3</Result>
    </Home>
    <Away>
      <Team>Manchester City</Team>
      <Result>31</Result>
    </Away>
  </Game>
....etc.....

I want to reporoduce the league table with the new results taken into consideration.

Thanks
>>
I am very interested though in how the node-set function is used.  I am assuming that it can be used
to create a resultant node-set, which can then be parsed to obtain the data.

<<
it is used to access a document/node-set created inside a variable
could you provide the structure of the league tables??
Avatar of psilli1

ASKER

The Structure is the first document!
version of Saxon??? 6.2.2??
Avatar of psilli1

ASKER

6.5.1
I shall make the presumption that you are using 6.5.1 and will use the node-set function as stated here:

node-set($fragment) When version="1.1", a result-tree-fragment is converted implicitly to a node-set if it is used in a context where a node-set is required. However, for portability with other XSLT 1.0 processors, it may be better to use the EXSLT node-set() function. The function takes a single argument that is a result tree fragment. Its function is to convert the result tree fragment to a node-set. The resulting node-set contains a single node, which is a root node (class DocumentInfo); below this are the actual nodes added to the result tree fragment, which may be element nodes, text nodes, or anything else. Note that a result tree fragment is not in general a well-formed document, for example there may be multiple element nodes or text nodes as children of the root.

http://saxon.sourceforge.net/saxon6.5.1/extensions.html#nodeset
Here is the XML Document, XSLT Document and the final output tested with Saxon 6.5.1


directive.xml
============================

<?xml version="1.0" encoding="iso-8859-1"?>
<document>
    <main filename="data.xml"/>
    <update filename="update.xml"/>
</document>

data.xml
=========
<?xml version="1.0" encoding="iso-8859-1"?>
<main>
<area>
<Name>North</Name>
<Team>
<TeamName>Manchester United</TeamName>
<League>
<Goals>
<For>100</For>
<Against>94</Against>
</Goals>
<WLTBreakdown Performance="home">
<Won>1</Won>
<Lost>0</Lost>
<Tied>0</Tied>
</WLTBreakdown>
<WLTBreakdown Performance="away">
<Won>1</Won>
<Lost>0</Lost>
<Tied>0</Tied>
</WLTBreakdown>
</League>
</Team>
<Team>
<TeamName>Manchester City</TeamName>
<League>
<Goals>
<For>50</For>
<Against>95</Against>
</Goals>
<WLTBreakdown Performance="home">
<Won>0</Won>
<Lost>0</Lost>
<Tied>1</Tied>
</WLTBreakdown>
<WLTBreakdown Performance="away">
<Won>0</Won>
<Lost>1</Lost>
<Tied>0</Tied>
</WLTBreakdown>            
</League>
</Team>
</area>
</main>

update.xml
==========
<?xml version="1.0" encoding="iso-8859-1"?>
<Score>
<Game>
<Home>
<Team>Manchester United</Team>
<Result>3</Result>
</Home>
<Away>
<Team>Manchester City</Team>
<Result>1</Result>
</Away>
</Game>
</Score>


saxon.xsl
=========
<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:saxon="http://icl.com/saxon" exclude-result-prefixes="saxon">
<xsl:output method="xml" version="1.0" encoding="iso-8859-1" indent="yes" />
<xsl:variable name="main" select="document(//main/@filename)/main" />
<xsl:variable name="update" select="document(//update/@filename)/score" />
<xsl:template match="/">
<xsl:apply-templates select="saxon:node-set($main)/node()" mode="update" />
</xsl:template>
<xsl:template match="@* | node()" mode="update">
<xsl:copy><xsl:apply-templates select="@* | node()" mode="update" /></xsl:copy>
</xsl:template>

<!--total goals for-->
<xsl:template match="Goals/For" mode="update">
<xsl:variable name="team" select="preceding::TeamName[1]" />
<xsl:variable name="for" select="sum(saxon:node-set($update)//Result[preceding-sibling::Team[1] = $team])" />
<For><xsl:value-of select=". + $for" /></For>
</xsl:template>

<!--total goals against-->
<xsl:template match="Goals/Against" mode="update">
<xsl:variable name="team" select="preceding::TeamName[1]" />
<xsl:variable name="home" select="sum(saxon:node-set($update)//Game[Away/Team[. = $team]]/Home/Result)" />
<xsl:variable name="away" select="sum(saxon:node-set($update)//Game[Home/Team[. = $team]]/Away/Result)" />
<Against><xsl:value-of select=". + $away + $home" /></Against>
</xsl:template>

<!--home details-->
<xsl:template match="WLTBreakdown[@Performance[. = 'home']]" mode="update">
<xsl:variable name="team" select="preceding::TeamName[1]" />
<xsl:variable name="won" select="count(saxon:node-set($update)//Game[Home[Team[. = $team]]/Result &gt; Away/Result])" />
<xsl:variable name="tied" select="count(saxon:node-set($update)//Game[Home[Team[. = $team]]/Result = Away/Result])" />
<xsl:variable name="lost" select="count(saxon:node-set($update)//Game[Home[Team[. = $team]]/Result &lt; Away/Result])" />
<WLTBreakdown Performance="home">
      <Won><xsl:value-of select="Won + $won" /></Won>
      <Lost><xsl:value-of select="Lost + $lost" /></Lost>
      <Tied><xsl:value-of select="Tied + $tied" /></Tied>
</WLTBreakdown>
</xsl:template>

<!--away details-->
<xsl:template match="WLTBreakdown[@Performance[. = 'away']]" mode="update">
<xsl:variable name="team" select="preceding::TeamName[1]" />
<xsl:variable name="won" select="count(saxon:node-set($update)//Game[Away[Team[. = $team]]/Result &gt; Home/Result])" />
<xsl:variable name="tied" select="count(saxon:node-set($update)//Game[Away[Team[. = $team]]/Result = Home/Result])" />
<xsl:variable name="lost" select="count(saxon:node-set($update)//Game[Away[Team[. = $team]]/Result &lt; Home/Result])" />
<WLTBreakdown Performance="away">
      <Won><xsl:value-of select="Won + $won" /></Won>
      <Lost><xsl:value-of select="Lost + $lost" /></Lost>
      <Tied><xsl:value-of select="Tied + $tied" /></Tied>
</WLTBreakdown>
</xsl:template>
</xsl:stylesheet>


for those wondering what is the equivalent in msxml, here is the stylesheet
msxml.xsl
=========
<?xml version="1.0" encoding="iso-8859-1"?>
<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 method="xml" version="1.0" encoding="iso-8859-1" indent="yes" />
<xsl:variable name="main" select="document(//main/@filename)" />
<xsl:variable name="update" select="document(//update/@filename)" />
<xsl:template match="/">
<xsl:apply-templates select="msxsl:node-set($main)/node()" mode="update" />
</xsl:template>
<xsl:template match="@* | node()" mode="update">
<xsl:copy><xsl:apply-templates select="@* | node()" mode="update" /></xsl:copy>
</xsl:template>

<!--total goals for-->
<xsl:template match="Goals/For" mode="update">
<xsl:variable name="team" select="preceding::TeamName[1]" />
<xsl:variable name="for" select="sum(msxsl:node-set($update)//Result[preceding-sibling::Team[1] = $team])" />
<For><xsl:value-of select=". + $for" /></For>
</xsl:template>

<!--total goals against-->
<xsl:template match="Goals/Against" mode="update">
<xsl:variable name="team" select="preceding::TeamName[1]" />
<xsl:variable name="home" select="sum(msxsl:node-set($update)//Game[Away/Team[. = $team]]/Home/Result)" />
<xsl:variable name="away" select="sum(msxsl:node-set($update)//Game[Home/Team[. = $team]]/Away/Result)" />
<Against><xsl:value-of select=". + $away + $home" /></Against>
</xsl:template>

<!--home details-->
<xsl:template match="WLTBreakdown[@Performance[. = 'home']]" mode="update">
<xsl:variable name="team" select="preceding::TeamName[1]" />
<xsl:variable name="won" select="count(msxsl:node-set($update)//Game[Home[Team[. = $team]]/Result &gt; Away/Result])" />
<xsl:variable name="tied" select="count(msxsl:node-set($update)//Game[Home[Team[. = $team]]/Result = Away/Result])" />
<xsl:variable name="lost" select="count(msxsl:node-set($update)//Game[Home[Team[. = $team]]/Result &lt; Away/Result])" />
<WLTBreakdown Performance="home">
      <Won><xsl:value-of select="Won + $won" /></Won>
      <Lost><xsl:value-of select="Lost + $lost" /></Lost>
      <Tied><xsl:value-of select="Tied + $tied" /></Tied>
</WLTBreakdown>
</xsl:template>

<!--away details-->
<xsl:template match="WLTBreakdown[@Performance[. = 'away']]" mode="update">
<xsl:variable name="team" select="preceding::TeamName[1]" />
<xsl:variable name="won" select="count(msxsl:node-set($update)//Game[Away[Team[. = $team]]/Result &gt; Home/Result])" />
<xsl:variable name="tied" select="count(msxsl:node-set($update)//Game[Away[Team[. = $team]]/Result = Home/Result])" />
<xsl:variable name="lost" select="count(msxsl:node-set($update)//Game[Away[Team[. = $team]]/Result &lt; Home/Result])" />
<WLTBreakdown Performance="away">
      <Won><xsl:value-of select="Won + $won" /></Won>
      <Lost><xsl:value-of select="Lost + $lost" /></Lost>
      <Tied><xsl:value-of select="Tied + $tied" /></Tied>
</WLTBreakdown>
</xsl:template>

</xsl:stylesheet>

xml output
==========
<?xml version="1.0" encoding="iso-8859-1"?>
<main><area><Name>North</Name>
<Team><TeamName>Manchester United</TeamName>
<League><Goals><For>103</For>
<Against>95</Against>
</Goals>
<WLTBreakdown Performance="home">
<Won>2</Won>
<Lost>0</Lost>
<Tied>0</Tied>
</WLTBreakdown>
<WLTBreakdown Performance="away">
<Won>1</Won>
<Lost>0</Lost>
<Tied>0</Tied>
</WLTBreakdown>
</League>
</Team>
<Team><TeamName>Manchester City</TeamName>
<League><Goals><For>51</For>
<Against>98</Against>
</Goals>
<WLTBreakdown Performance="home">
<Won>0</Won>
<Lost>0</Lost>
<Tied>1</Tied>
</WLTBreakdown>
<WLTBreakdown Performance="away">
<Won>0</Won>
<Lost>2</Lost>
<Tied>0</Tied>
</WLTBreakdown>
</League>
</Team>
</area>
</main>

Notes
=====
1. It is much simpler using the element transformation technique seen here to update the original transform.

2. To see the transform, I used the command line
java -jar saxon.jar "directive.xml" "saxon.xsl" and the output was exactly the same as that for msxml.xsl

3. by using the element transformation technique, we leave untouched elements that we wish to pass thru untouched like TeamName element and area.

4. The templates after
<xsl:template match="@* | node()" mode="update">
<xsl:copy><xsl:apply-templates select="@* | node()" mode="update" /></xsl:copy>
</xsl:template>

targets the elements that we interested in updating.

Regards,

Brandon Driesen
ASKER CERTIFIED SOLUTION
Avatar of b1xml2
b1xml2
Flag of Australia image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
feedback, please?!
Avatar of psilli1

ASKER

Sorry, ur code gave me a vgood base as to how to use the node-set command, and from this i have been able to produce the XSL to create the new XML document.

Thanks for ur help!

Also, u may be able to help me on one last thing, I have a comma separated value in one of my elements, is there a way of spliting this then looping throuh the results creating a new element for each?

If not then no problem, and tnx 4 the help.
Hi,

Have a look at this question too.

https://www.experts-exchange.com/jsp/qManageQuestion.jsp?ta=xml&qid=20321652

Thanks
vijayneema