Rename nodes using XSLT

I am trying something very simple, but for some reason this is not working. Basically, I need to rename some nodes in the XML document. So I created an XSLT file for conversion.

Here is an example XML:

EDIT: Addresses and address elements are found at many levels. That's why I had to try applying XSLT. The Visual Studio dataset function, which creates typed datasets from XSD files, does not allow you to have nested references to the same table. Thus, the presence of Business / Business / Addresses and Business / Business / Contact / Addresses causes Load () to fail. This is a known issue, and all they tell you is something like "Don't have nested table links ... edit your XSD to stop this." Unfortunately, this means that we must use XSLT so that the XML matches the cracked XSD, as the files come from a third-party provider.

So, we are very close with the help provided here. The last two things:

1.) How do I use the namespace link in the xsl: template matching attribute to indicate that I want to rename business / business / addresses to BusinessAddresses, but rename Business / Business / Contacts / Contacts / Addresses to ContactAddresses?

2.) How can I stop XSLT from cluttering up each new item with explicit namespace references? This causes a strong inflation in the outlet.

I created a namespace called steel, and I had a good success:

<xsl:template match="steel:Addresses> <xsl:element name="BusinessAddresses> </xsl:template> 

The obvious problem is that it renames ALL Address elements in BusinessAddresses, although I want some of them to be called ContactAddresses, etc. Adding useless explicit namespace references to all renamed nodes also causes problems.

I tried things like this, but as soon as I add slashes to the match attribute, this is a syntax error in XSLT, for example:

 <xsl:template match="steel:/Businesses/Business/Addresses"> 

I feel very close, but you need to be guided by how to mix the use of namespace and the way to use a slash to select ANY nodes in certain ways.

 <?xml version="1.0"?> <Businesses> <Business> <BusinessName>Steel Stretching</BusinessName> <Addresses> <Address> <City>Pittsburgh</City> </Address> <Address> <City>Philadelphia</City> </Address> </Addresses> <Contacts> <Contact> <FirstName>Paul</FirstName> <LastName>Jones</LastName> <Addresses> <Address> <City>Pittsburgh</City> </Address> </Addresses> </Contact> </Contacts> </Business> <Business> <BusinessName>Iron Works</BusinessName> <Addresses> <Address> <City>Harrisburg</City> </Address> <Address> <City>Lancaster</City> </Address> </Addresses> </Business> </Businesses> 

I need to rename Addresses to BusinessAddresses, and I need to rename Address to BusinessAddress, for each instance of Addresses and Address directly to Business node. I also need to rename the Addresses in ContactAddresses, and I need to rename the address in ContactAddress for each instance of Addresses and addresses directly in the contact node.

I tried several solutions, but no one works. All of them produce the same XML as the source file.

Here is an example of what I tried:

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

This has been tested in at least 6 different variations, including the XSLT step-by-step debugger in VB.Net. It never performs pattern matching for addresses.

Why?

+6
xml xslt
source share
2 answers

Why may XSLT fail?

XSLT will fail due to obvious things like typos. However, the most likely situation involves using the namespace. If you declared a default namespace for your XML, but do not include it in your XSLT, XSLT will not match the patterns as you might expect.

The following example adds the xmlns:business attribute, which declares that the elements identified by the business prefix belong to the mynamespace.uri namespace. Then I used this prefix to match the address and address pattern. Of course, you will need to change the namespace URI to whatever matches the default namespace of your XML file.

 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" xmlns:business="mynamespace.uri" exclude-result-prefixes="msxsl"> <xsl:template match="/"> <xsl:apply-templates select="@*|node()"/> </xsl:template> <xsl:template match="@*|node()"> <xsl:copy> <xsl:apply-templates select="@*|node()"/> </xsl:copy> </xsl:template> <xsl:template match="business:Addresses"> <xsl:element name="BusinessAddresses"> <xsl:apply-templates select="@*|node()" /> </xsl:element> </xsl:template> <xsl:template match="business:Address"> <xsl:element name="BusinessAddress"> <xsl:apply-templates select="@*|node()"/> </xsl:element> </xsl:template> </xsl:stylesheet> 

How do you match patterns based on element location as well as name?

There are several ways to achieve this last part of your problem: BusinessAddress or ContactAddress, but the easiest way is to change the attributes of the match template to consider the parent nodes. If you consider the match attribute as the path in the XML for the node, this option becomes clearer (the contents of the templates left for brevity):

 <xsl:template match="business:Business/business:Addresses> </xsl:template> <xsl:template match="business:Business/business:Addresses/business:Address"> </xsl:template> <xsl:template match="business:Contact/business:Addresses"> </xsl:template> <xsl:template match="business:Contact/business:Addresses/business:Address"> </xsl:template> 

There are other methods to achieve this, if match remains based only on the name of the element, but they are more difficult to implement, follow and maintain, since they involve the use of conditional checks of the parent hierarchy of the node being processed element, all inside the template.

+9
source share

Perhaps this is if the data you show is really similar to what you need to work with

 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:template match="Businesses"> <Businesses> <xsl:apply-templates/> </Businesses> </xsl:template> <xsl:template match="*"> <xsl:copy-of select="."/> </xsl:template> <xsl:template match="Addresses"> <BusinessAddresses> <xsl:apply-templates/> </BusinessAddresses> </xsl:template> <xsl:template match="Addresses/Address"> <BusinessAddress> <xsl:value-of select="."/> </BusinessAddress> </xsl:template> </xsl:stylesheet> 
0
source share

All Articles