Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Westi on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

XML flat hierarchy help 1

Status
Not open for further replies.

jiefwu

IS-IT--Management
Jan 23, 2007
5
US
Hi i'm looking to get the following XML code:
------------------------------------------------------------
<pod:contactDetail>
<pod:contactRowID>contactRowID</pod:contactRowID>
<pod:customerAccount>customerAccount</pod:customerAccount>
<pod:individual>individual</pod:individual>
<pod:person>
<pod:name>
<pod:nameElement>PersonName</pod:nameElement>
<pod:nameValue>nameValue</pod:nameValue>
</pod:name>
<pod:middleName>middleName</pod:middleName>
<pod:contactWorkPhone>contactWorkPhone</pod:contactWorkPhone>
</pod:person>
</pod:contactDetail>
-----------------------------------------------------------

into this form:

contactDetail
contactDetail/contactRowID
contactDetail/customerAccount
contactDetail/individual
contactDetail/person
contactDetail/person/name
contactDetail/person/name/nameElement
contactDetail/person/name/nameValue
contactDetail/person/middleName
contactDetail/person/contactWorkPhone


how do i go about this? currently it is a _very_ manual process and with thousands of fields i'm not looking forward to it! i'm using Altova XML Spy.

any help is appreciated
cheers
jiefwu
 
jiefwu,

Welcome to Tek-Tips.

The normal means of doing this would be to write an XSLT stylesheet. I am not sure what your desired output means but you should be able to use Altova's XSLT tool to transform the input document into the desired output.

Tom Morrison
 
the desired output is to flatten out the XML Structure to the element level in order to write descriptions for each element.

how would i go about writing the XSLT stylesheet to achieve this? i have AltovaStyleVision if that helps.

any others options?
 
When you indicate this
Code:
contactDetail
contactDetail/contactRowID
contactDetail/customerAccount
contactDetail/individual
contactDetail/person
contactDetail/person/name
contactDetail/person/name/nameElement
contactDetail/person/name/nameValue
contactDetail/person/middleName
contactDetail/person/contactWorkPhone

...do you mean that you wish to create a text file that looks like this, or do you want some sort of alternative XML file output?

In either case, the XSLT stylesheet is fairly straightforward.
Code:
<?xml version='1.0'?>
<xsl:stylesheet version="1.0" xmlns:xsl="[URL unfurl="true"]http://www.w3.org/1999/XSL/Transform">[/URL]
<xsl:output method="text"/>

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

<xsl:template match="*">
	<xsl:variable name="countNodes" select="count(ancestor-or-self::*)"/>
	<xsl:for-each select="ancestor-or-self::*">
		<xsl:value-of select="local-name(.)"/>
		<xsl:if test="position() != $countNodes">
			<xsl:text>/</xsl:text>
		</xsl:if>
	</xsl:for-each>
	<xsl:text>
</xsl:text>
	<xsl:apply-templates select="*"/>
</xsl:template>

</xsl:stylesheet>
Code:
contactDetail
contactDetail/contactRowID
contactDetail/customerAccount
contactDetail/individual
contactDetail/person
contactDetail/person/name
contactDetail/person/name/nameElement
contactDetail/person/name/nameValue
contactDetail/person/middleName
contactDetail/person/contactWorkPhone

Tom Morrison
 
Hi Tom,

I'm looking for text-based output, however either case will give me the output as above.

do i need to fill in anything in the all the areas marked "*" ? (i.e. 'contactDetail') ?

do i press 'XSL Transformation' and choose the XML file to be transformed?

thanks for the help.


 
I am not an Altova user, so I cannot help with the mechanics of all this on Altova. (I use Stylus Studio. Same idea, different user interface.)

The XSLT is fine as is. It should work to flatten any XML fed to it. Think of the * characters as a wild card which can select multiple nodes of the input XML document. The output that I show in the third CODE box is actual text output of the XSL transformation using the XML from your original post.

So, I would think that you should copy the XSLT to a file probably with an extension of .xsl, then - as you suggest -- select XSL Transformation using that xsl file and choose the XML file to be transformed as the input document.

Tom Morrison
 
Hi Tom, thanks for the quick response,

cheers that works great.
i'm wondering what modifications need to be made to only output the element-level(lowest level) hierarchy/path?

thanks a lot
jiefwu
 
Code:
<?xml version='1.0'?>
<xsl:stylesheet version="1.0" xmlns:xsl="[URL unfurl="true"]http://www.w3.org/1999/XSL/Transform">[/URL]
<xsl:output method="text"/>

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

<xsl:template match="*">
    <xsl:value-of select="local-name(.)"/>
    <xsl:text>
</xsl:text>
    <xsl:apply-templates select="*"/>
</xsl:template>

</xsl:stylesheet>

Tom Morrison
 
Hi Tom, thanks for that. it has been a great help and has save many hours of work!

finally how would you go an XSLT to attain the flat-hierarchy for this code:

Code:
<xs:complexType name="Party">					
	<xs:annotation>				
		<xs:documentation>Business Entity</xs:documentation>			
	</xs:annotation>				
	<xs:sequence>				
		<xs:element name="name" minOccurs="0">			
			<xs:complexType>		
				<xs:sequence maxOccurs="unbounded">	
					<xs:element name="nameElement" type="xs:string"/>
					<xs:element name="nameValue" type="xs:string"/>
				</xs:sequence>	
			</xs:complexType>		
		</xs:element>			
		<xs:element name="identifier" type="GlobalIdentifier" minOccurs="0" maxOccurs="unbounded"/>			
		<xs:element name="employee" type="Employment" minOccurs="0"/>			
		<xs:element name="employer" type="Employment" minOccurs="0"/>			
		<xs:element name="contactDetail" minOccurs="0">	
<xs:complexType name="PaymentMethod">
	<xs:sequence>
		<xs:element name="code" type="xs:string"/>
		</xs:sequence>	
	</xs:complexType>	

etc...
i am just looking to get the complex type and its subsequent element names down into this form:

party/name/nameElement
party/name/nameValue
party/identifier
party/employee
party/empoyer
party/contactDetail
paymentMethod/code

etc...
 
I don't see the logic behind the last output line. If that's just a typo, you can do it something like this.
[tt]
<?xml version="1.0" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="<xsl:eek:utput method="text" encoding="utf-8" />
<xsl:template match="/">
<xsl:apply-templates select="//*[local-name()='complexType']" />
</xsl:template>
<xsl:template match="*">
<xsl:if test="@name">
<xsl:for-each select="ancestor-or-self::*">
<xsl:value-of select="@name" />
<xsl:if test="@name and not(position()=last())"><xsl:text>/</xsl:text></xsl:if>
<xsl:if test="position()=last()"><xsl:text>&#x0d;&#x0a;</xsl:text></xsl:if>
</xsl:for-each>
</xsl:if>
<xsl:apply-templates select="*" />
</xsl:template>
</xsl:stylesheet>
[/tt]
 
jiefwu,

First, note that XML Schema is itself an XML document, so there is no problem transforming an XML Schema with XSLT.

You could use the same XSLT that I have previously provided, which provides the basic recursive traversal of the input document tree. The change is that you will be conditioning output based upon "local-name()='element'" and you will be getting the value to output from '@name'.

Why don't you give the modifications a try and come back if you need help.

Tom Morrison
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top