I have XML data where information in nodes relate to other nodes. I am trying to figure out how to generate output based on these relationships.

XML sample
<gedcom>
<indi id="@I001">
<famc>@F002@</famc>
</indi>
...
<fam id="@F002">
<husb>@I005@</husb>
<wife>@I007@</wife>
</fam>
</gedcom>

XSLT sample
<xsl:template match="/">
<xsl:apply-templates select="/gedcom/indi[@id='@I001@']"/>
</xsl:template>

<xsl:template match="indi">
<xsl:value-of select="name/text()"/>

<!-- select the ID of the related FAM node -->
<xsl:variable name="parentsFamily" select="famc/text()"/>

<!-- apply the FAM template to the FAM node reference in the above FAMC node -->
<xsl:apply-templates select="/gedcom/fam[@ID=$parentsFamily]"/>
</xsl:template>

<xsl:template match="fam">
Test
</xsl:template>

The above does not work, but hopefully gives an idea of what I am trying to do. Ultimately I would like to recurse through INDI nodes to related FAM nodes back to related INDI nodes.

Is this even possible with basic XSLT and XPATH functionality?

Recommended Answers

All 4 Replies

xml for testing

<gedcom>
	<indi id="@I001">
		<famc>@F002@</famc>
	</indi>
	<fam id="@F002">
		<husb>@I005@</husb>
		<wife>@I007@</wife>
	</fam>
</gedcom>

xsl

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
	<xsl:output indent="yes" method="xml"/>
	<xsl:template match="/">
		<root>
			<xsl:apply-templates select="gedcom"/>
		</root>
	</xsl:template>
	<xsl:template match="gedcom">
		<xsl:apply-templates select="indi"/>
	</xsl:template>
	<xsl:template match="indi">
		<xsl:apply-templates select="famc"/>
	</xsl:template>
	<xsl:template match="famc">
		<famc>
			<where>
				<xsl:value-of select="."/>
			</where>
<!-- delete last sign @ and select the node 2 level back in same level as 
node fam indi
-->
			<xsl:variable name="data" select="substring(.,1,string-length(.)-1)"/>
			<xsl:apply-templates select="../../fam[@id=$data]"/>
		</famc>
	</xsl:template>
	<xsl:template match="fam">
		<datainfam>
				<xsl:apply-templates/>
		</datainfam>
	</xsl:template>
	<xsl:template match="husb|wife">
		<data>
			<xsl:value-of select="concat(local-name(.),' ',.)"/>
		</data>
	</xsl:template>
</xsl:stylesheet>

result

<?xml version='1.0' ?>
<root>
  <famc>
    <where>@F002@</where>
    <datainfam>
		
      <data>husb @I005@</data>
		
      <data>wife @I007@</data>
	
    </datainfam>
  </famc>
</root>

Thank You XML Looser

But applying your code to my XML does not produce the expected output.

<root>
  <famc>
    <where>@F002@</where>
  </famc>
  <famc>
    <where>@F003@</where>
  </famc>
  <famc>
    <where>@F001@</where>
  </famc>
  ...
</root>

As you can see there is no datainfam nor their data nodes.

I see now that I mistyped the XML in my first example. All the ID values are escaped by two @ symbols.

<gedcom>
  <indi id="@I001@">
    <famc>@F002@</famc>
  </indi>
  ...
  <fam id="@F002@">
    <husb>@I005@</husb>
    <wife>@I007@</wife>
  </fam>
</gedcom>

So with that expectation, I simplified the famc match block.

<xsl:template match="famc">
  <famc>
    <where>
      <xsl:value-of select="."/>
    </where>

    <xsl:variable name="data" select="."/>
    <xsl:apply-templates select="../../fam[@id=$data]"/>
  </famc>
</xsl:template>

And this did not produce the desired output. I don't see how my correction would have broken things. I wonder if this could be a difference in parsers?

Never mind!

I just corrected an incorrect case in one of the lines of code.

Now, I will play with this and see if I can get it to produce the desired HTML output!

Thanks again XML Looser. Your code has given me a very good start, I hope.

a template descrip what will do when node is found by parser
all xml docment have an root element
so we can write the html code which is in the output display
with xsl:apply-templates select="gedcom" fetch the data and open table

<xsl:template match="/">
		<html>
			<style>
			table{border :black 2px solid}
			th,td{border :black 2px solid}
			</style>
			<table>
				<tr>
					<th>where</th>
					<th>item</th>
					<th>item</th>
				</tr>
				<xsl:apply-templates select="gedcom"/>
			</table>
		</html>
	</xsl:template>

use predicate as if in programming languarge

<xsl:variable name="data" select="substring(.,1,string-length(.)-1)"/>
<xsl:apply-templates select="../../fam[@id=$data]"/>

when data found put the value in a table

<xsl:template match="husb|wife">
		<td>
			<xsl:value-of select="concat(local-name(.),' ',.)"/>
		</td>
	</xsl:template>

xml tesdata

<gedcom>
	<indi id="@I001">
		<famc>@F002@</famc>
	</indi>
	<fam id="@F002">
		<husb>@I005@</husb>
		<wife>@I007@</wife>
	</fam>
	<indi id="@I001">
		<famc>@F003@</famc>
	</indi>
	<fam id="@F003">
		<husb>@I015@</husb>
		<wife>@I017@</wife>
	</fam>
</gedcom>

xsl

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
	<xsl:output indent="yes" method="html"/>
	<xsl:template match="/">
		<html>
			<style>
			table{border :black 2px solid}
			th,td{border :black 2px solid}
			</style>
			<table>
				<tr>
					<th>where</th>
					<th>item</th>
					<th>item</th>
				</tr>
				<xsl:apply-templates select="gedcom"/>
			</table>
		</html>
	</xsl:template>
	<xsl:template match="gedcom">
		<xsl:apply-templates select="indi"/>
	</xsl:template>
	<xsl:template match="indi">
		<xsl:apply-templates select="famc"/>
	</xsl:template>
	<xsl:template match="famc">
		<tr>
			<td>
				<xsl:value-of select="."/>
			</td>
			<xsl:variable name="data" select="substring(.,1,string-length(.)-1)"/>
			<xsl:apply-templates select="../../fam[@id=$data]"/>
		</tr>
	</xsl:template>
	<xsl:template match="fam">
		<xsl:apply-templates/>
	</xsl:template>
	<xsl:template match="husb|wife">
		<td>
			<xsl:value-of select="concat(local-name(.),' ',.)"/>
		</td>
	</xsl:template>
</xsl:stylesheet>

result

<html>
  <style>
			table{border :black 2px solid}
			th,td{border :black 2px solid}
			</style>
  <table>
    <tr>
      <th>where</th>
      <th>item</th>
      <th>item</th>
    </tr>
    <tr>
      <td>@F002@</td>
		<td>husb @I005@</td>
		<td>wife @I007@</td>
	</tr>
    <tr>
      <td>@F003@</td>
		<td>husb @I015@</td>
		<td>wife @I017@</td>
	</tr>
  </table>
</html>
Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.