1

Hello i'm having troubles with xslt and I would appreaciate greatly your help,

I've got an xml with some data I want to parse using xslt and a template file with the data structure and default values for the empty nodes.

I want to generate an xml using the template structure using the default values or the data given by the input xml depending on whether it has text or is empty.

I've tried iterating the nodes but I'm new to xsl and i don't get anything clear, thanks in advance.

Data:

<doc>
   <object>
      <group1> 
          <a>(<p>text here</p> or blank)</a>
          <b>(<p>text here</p> or blank)</b>
          <c>
             <c1>(<p>text here</p> or blank)</c1>
             <c2>(<p>text here</p> or blank)</c2>
          </c>
      </group1>
      <group2>
          <d>(<p>text here</p> or blank)</d>
      </group2>
   </object>
</doc>

Template:

<doc>
   <object>
      <group1> 
          <a><p>default text</p></a>
          <b><p>default text</p></b>
          <c>
             <c1><p>default text</p></c1>
             <c2><p>default text</p></c2>
          </c>
      </group1>
      <group2>
          <d><p>default text</p></d>
      </group2>
   </object>
</doc>

Right now I'm generating the output xml evaluating every node like this:

<xsl:variable name="file" select="document('template.xml')"/>    
<a>
    <xsl:choose>
        <xsl:when test="//a != ''">
              <xsl:copy-of select="//a/p" />
        </xsl:when>
        <xsl:otherwise>
              <xsl:copy-of select="$file//a/p" />
        </xsl:otherwise>
    </xsl:choose> 
</a>
<b> ... </b> ...

The code to iterate that i'm trying which results in all blank:

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

<xsl:template match="*[not(*) and not(text())]">
    <xsl:copy>
        <xsl:apply-templates select="$file//*[name()=name(current())]/p"/>
    </xsl:copy>
</xsl:template>
1

2 Answers 2

0

What are you using to parse your xml file ? Saxon ?

You can test replacing

<xsl:copy-of select="..." />

By

<xsl:value-of select="..." />

But I don't think the problem is here. You have to run through all your nodes recursively and in a Blank case, you should parse the 'Template.xml' value at this node.

Test something like :

<xsl:template match="*">
   <xsl:choose>
    <xsl:when test="not(Current()='')">
          <xsl:value-of select="." />
    </xsl:when>
    <xsl:otherwise>
          <xsl:copy-of select="$file/name(Current())" />
    </xsl:otherwise>
</xsl:choose> 
</xsl:template>

It doesn't work I think, because I can't test now and I forgot the syntax but it should be something like this.

Sign up to request clarification or add additional context in comments.

2 Comments

I actually don't have any way to trace xslt errors, but the result is just blank. I've edited the post with the code i'm trying
I think your first template never select the second in your general apply-template. I edited my answer
0

I've finally resolved it, I'm posting my solution here:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="/*">
        <doc xml:lang="es">
            <xsl:apply-templates select="*"/>
        </doc>
    </xsl:template> 

    <xsl:template match="*">
        <xsl:copy>
            <xsl:choose>
              <xsl:when test="current() != ''">
                <xsl:choose>
                    <xsl:when test="self::p">
                        <xsl:copy-of select="node()"/>
                    </xsl:when>
                    <xsl:otherwise>
                        <xsl:apply-templates select="*"/>
                    </xsl:otherwise>
                </xsl:choose>
              </xsl:when>
              <xsl:otherwise>
                <xsl:variable name="file" select="document('template.xml')"/>
                <xsl:copy-of select ="$file//*[name()=name(current())]/p"/>
              </xsl:otherwise>
            </xsl:choose>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

2 Comments

This code will do the trick as long as you don't need to distinguish between 'group1/a' and 'group2/a', i.e. as long as the name of the context node is adequate to identify the replacement text. I have a couple of solutions in mind that might work if you need to identify replacement text by longer XPaths. BTW, your code outputs an extra 'object' element.
True, I just made a renaming from my actual code in which the input xml is slightly diferent (doesn't have the doc node), anyway i edited it to remove the first object. In my case the nodes in my template are all unique so it doesn't matter but if you can figure out a way to actually get the complete xpath from the node It would be great to know.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.