2

My Source XML sample looks like this.

<?xml version="1.0" encoding="ISO-8859-1"?>
<catalog>
    <cd>
        <T>A Book</T>
        <A>A Man</A>
        <D>Today</D>
    </cd>
</catalog>

While 'T' means Title,'A' means Author,'D' means Date. The output I want to get looks like this:

Title:A Book. Author:A Man. Date:Today

According to Implementing Key Value Concept in XSLT,I find that I can wirite the XSLT like this:

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

 <my:codes>
   <code key="T" value="Title"/>
   <code key="A" value="Author"/>
   <code key="D" value="Date"/>
 </my:codes>

 <xsl:key name="kCodeByName" match="code" use="@key"/>

 <xsl:template match="/">
     <xsl:for-each select="catalog/cd/*">
        <xsl:apply-templates select="."/>:<xsl:value-of select="."/>.
     </xsl:for-each>
 </xsl:template>

 <xsl:template match= "node()[name() = document('')/*/my:codes/*/@key]">

  <xsl:variable name="vCur" select="name()"/>

  <xsl:for-each select="document('')">
      <xsl:value-of select=
       "key('kCodeByName', $vCur)/@value"/>
  </xsl:for-each>
 </xsl:template>
</xsl:stylesheet>

But if I want to use

<xsl:apply-templates select="name()"/>:<xsl:value-of select="."/>.

rather than

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

What should I change in XSLT?

Tim C
  • 70,053
  • 14
  • 74
  • 93
ArchStacker
  • 35
  • 1
  • 7

1 Answers1

1

name() is a function, not a node; you cannot apply templates to it or use it in a match pattern.

Why don't you do simply:

XSLT 1.0

<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:strip-space elements="*"/>

<xsl:variable name="codes">
   <code key="T" value="Title"/>
   <code key="A" value="Author"/>
   <code key="D" value="Date"/>
</xsl:variable>

<xsl:key name="kCodeByName" match="code" use="@key"/>

<xsl:template match="cd">
    <xsl:apply-templates/>
    <xsl:text>&#10;</xsl:text>  
</xsl:template>

<xsl:template match="cd/*">
    <xsl:variable name="vCur" select="name()"/>
    <xsl:for-each select="document('')">
        <xsl:value-of select="key('kCodeByName', $vCur)/@value"/>
    </xsl:for-each>
    <xsl:text>:</xsl:text>      
    <xsl:value-of select="."/>
    <xsl:if test="position()!=last()">
        <xsl:text>. </xsl:text> 
    </xsl:if>
</xsl:template>

</xsl:stylesheet>

Edit

If you prefer, you can change the last template to:

<xsl:template match="cd/*">
    <xsl:call-template name="lookup">
        <xsl:with-param name="key" select="name()"/>
    </xsl:call-template>
    <xsl:text>:</xsl:text>      
    <xsl:value-of select="."/>
    <xsl:if test="position()!=last()">
        <xsl:text>. </xsl:text> 
    </xsl:if>
</xsl:template>

and add:

<xsl:template name="lookup">
    <xsl:param name="key"/>
    <xsl:for-each select="document('')">
        <xsl:value-of select="key('kCodeByName', $key)/@value"/>
    </xsl:for-each>
</xsl:template>
michael.hor257k
  • 113,275
  • 6
  • 33
  • 51
  • It works,but can you wrap the important part in a template or a function? Because I may use this way to translate a xsl by create a One language-Another language list, and wrap all the text in the xsl. So it's better to do the transform in one line like `` in my post or like `` in [here](https://stackoverflow.com/questions/13938765/xsl-list-of-words-to-replace-most-easy-defintion).And I think what I need should work likes a function,the param can be `text()` or `name()` or other string. – ArchStacker Jul 21 '15 at 15:09
  • @ArchStacker There are no user-defined functions in XSLT 1.0, but you can call a named template. I am not sure what's the exact advantage of doing so here, but I have added this option to my answer. – michael.hor257k Jul 21 '15 at 15:57
  • But it still need two lines to do it.Maybe what I need now is a marco like [this](https://stackoverflow.com/questions/3450889/xsl-macros-how-to-create-a-macro-that-will-replace-call-template-with-par)? But according to the answers in that question there is no way to do it with XSLT 1.0? – ArchStacker Jul 22 '15 at 00:10
  • @ArchStacker XSLT is naturally verbose. XSLT 1.0 even more than 2.0. That's just how it is - best get used to it. -- If you really want, you can call the template without a parameter. Calling a named template does not change the context, so you can just as well call the name() function in the named template. But I don't think that's good code. – michael.hor257k Jul 22 '15 at 00:48