tags:

views:

65

answers:

4

Essentially, I have XML structured like this:

<A>
 <B>
  <1>data</1>
  <2>data</2>
  <C>
   <1>data</1>
   <2>data</2>
   <B>
    <1>data</1>
    <2>data</2>
    <C>
     <B>
      <1>data</1>
      <2>data</2>
     </B>
    </C>
   </B>
   <B>
    <1>data</1>
    <2>data</2>
   </B>
  </C>
 </B>
</A>

I am trying to get the output to look like this:

<A>
<B 1="data" 2="data">
    <C 1="data" 2="data">
        <B 1="data" 2="data">
            <C>
                <B 1="data" 2="data" >
                </B>
            </C>
        </B>
        <B 1="data" 2="data" >
        </B>
    </C>
</B>
</A>

I have figured out how to put everything as attributes and start looping through the elements. The issue I am facing is that when trying to get below the first C, nothing happens. Here is my code:

<?xml version="1.0" encoding="utf-8"?>
<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" indent="yes"/>

  <xsl:template match="/">
    <MenuDataResult>
      <B>
        <xsl:apply-templates />
      </B>
    </MenuDataResult>
  </xsl:template>

  <xsl:template match="B">
        <xsl:for-each select="B">
          <B ItemID="{B/ItemID/text()}" ItemType="{ItemType/text()}" ItemSubType="{ItemSubType/text()}"
                  ItemTitle="{ItemTitle/text()}" ItemImage="{ItemImage/text()}" ItemImageOverride="{ItemImageOverride/text()}"
                ItemLink="{ItemLink/text()}" ItemTarget="{ItemTarget/text()}>">
            <xsl:for-each select="C">
              <xsl:apply-templates select="C"/>
            </xsl:for-each>
          </B>
        </xsl:for-each>
  </xsl:template>

  <xsl:template match="C">
    <C ID="{ID/text()}" Title="{Title/text()}" Template="{Template/text()}"
          Type="{Type/text()}" Link="{Link/text()}" ParentID="{ParentID/text()}"
          AncestorID="{AncestorID/text()}" FolderID="{FolderID/text()}" Description="{Description/text()}"
          Image="{Image/text()}" ImageOverride="{ImageOverride/text()}">
      <xsl:for-each select="B">
        <xsl:apply-templates select=".//B"/>
      </xsl:for-each>
    </C>
  </xsl:template>

</xsl:stylesheet>
A: 
<xsl:apply-templates select=".//B"/>

might be a problem IMO. you probably need to call the template.

//B would mean Root/B.

Correct me if i am wrong.

Yogendra
+1  A: 

In your example you have path A/B/C/B/C/B/1 = data

<xsl:template match="C">
    # context() = A/B/C
.. 
  <xsl:for-each select="B">
    # context() = A/B/C/B
    # selects every B descendent of the current B
    <xsl:apply-templates select=".//B"/>
       # context() = A/B/C/B/C/B/
  </xsl:for-each>
</xsl:template>


<xsl:template match="B">
  # context() = A/B/C/B/C/B/
  <xsl:for-each select="B">
     # there are no B's under this B - only 1 and 2 so nothing selected
  </xsl:for-each>
</xsl:template>

You seem to be nesting extra for-eachs and selecting deeper than you need to be. Just having <xsl:apply-templates select="B|C"> in your C template to process any directly nested Bs or Cs, and the same inside your B template. At the moment, it's selecting only Bs within Bs within Bs.

Pete Kirkham
A: 

With proper input:

<A> 
 <B> 
  <a1>data</a1> 
  <a2>data</a2> 
  <C> 
   <a1>data</a1> 
   <a2>data</a2> 
   <B> 
    <a1>data</a1> 
    <a2>data</a2> 
    <C> 
     <B> 
      <a1>data</a1> 
      <a2>data</a2> 
     </B> 
    </C> 
   </B> 
   <B> 
    <a1>data</a1> 
    <a2>data</a2> 
   </B> 
  </C> 
 </B> 
</A> 

And this stylesheet:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

<xsl:template match="@*|node()">
 <xsl:copy>
  <xsl:apply-templates select="@*" />
  <xsl:apply-templates select="a1|a2" />
  <xsl:apply-templates select="node()[not(contains('a1|a2',name()))]" />
 </xsl:copy>
</xsl:template>

<xsl:template match="a1|a2">
 <xsl:attribute name="{name()}" >
  <xsl:value-of select="." />
 </xsl:attribute>
</xsl:template>

</xsl:stylesheet>

You'll get the desired output:

<A>
 <B a1="data" a2="data">
  <C a1="data" a2="data">
   <B a1="data" a2="data">
    <C>
     <B a1="data" a2="data">
     </B>
    </C>
   </B>
  <B a1="data" a2="data">
  </B>
  </C>
 </B>
</A>
Alejandro
We don't often get to chose our input. In fact the goal here appears to be converting to a valid format. Perhaps this means that XSLT is not a good tool for the problem but hand waving the input into a better format probably isn't helpful.
Bradley Harris
@Bradley Harris: You must be careful with your down votes. Taking into account what is written in question ("I have XML structured like this") and the stylesheet (check the patterns in templates), it becomes clear that the input document is an example. The commentary on the need for proper input document was made on the question of the user, therefore there should have been yours, for clarity.
Alejandro
Actually, I did not down vote this answer. In fact I think it contains useful information. I just wanted to point out that it might not be helpful in solving the original problem.
Bradley Harris
A: 

In the spirit of XSLT: this transformation:

<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"&gt;
    <xsl:output omit-xml-declaration="yes" indent="yes"/>
    <xsl:strip-space elements="*"/>

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

 <xsl:template match="a1|a2">
  <xsl:attribute name="{name()}">
    <xsl:value-of select="."/>
  </xsl:attribute>
 </xsl:template>
</xsl:stylesheet>

when applied on the corrected XML document from Alejandro's example:

<A>
 <B>
  <a1>data</a1>
  <a2>data</a2>
  <C>
   <a1>data</a1>
   <a2>data</a2>
   <B>
    <a1>data</a1>
    <a2>data</a2>
    <C>
     <B>
      <a1>data</a1>
      <a2>data</a2>
     </B>
    </C>
   </B>
   <B>
    <a1>data</a1>
    <a2>data</a2>
   </B>
  </C>
 </B>
</A>

produces the desired, correct output:

<A>
   <B a1="data" a2="data">
      <C a1="data" a2="data">
         <B a1="data" a2="data">
            <C>
               <B a1="data" a2="data"/>
            </C>
         </B>
         <B a1="data" a2="data"/>
      </C>
   </B>
</A>
Dimitre Novatchev