Вопрос

have got a XML like this:

<?xml version="1.0" encoding="utf-8" ?>
<root xmlns:xlink="http://www.w3.org/1999/xlink"  xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"  xmlns:skos="http://www.w3.org/2004/02/skos/core#"  version="2.8.1"  vocab-version="2013-02-28" >
  <section1>
    <a xml:id="a100">
      <ref xlink:href="#aXXX"/>
      <ref xlink:href="#aYYY"/>
    </a>
  </section1>
  <section2>
    <b xml:id="aXXX">
      DataB
    </b>
    <c xml:id="aYYY">
      DataC
    </c>
    </section2>
</root>

I want to apply the following XSLT:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xlink="http://www.w3.org/1999/xlink">
    <xsl:output method="text"  indent="yes"/>
    <xsl:strip-space elements="*" />
    <xsl:preserve-space elements="db:para db:literallayout" />
    <xsl:param name="code" />
    <xsl:key name='mykeys' match='/root/section2/*' use='concat("#", @xml:id)'/>

    <xsl:template match="/" >
        <xsl:apply-templates select='/root/section1/a/ref'>
        </xsl:apply-templates>
    </xsl:template>

    <xsl:template match="ref">
        <xsl:apply-templates select='key("mykeys", @xlink:href)' >
        </xsl:apply-templates>
    </xsl:template>

    <xsl:template match='b | c' >
        <xsl:value-of select="."  />
    </xsl:template>

</xsl:stylesheet>

I want to have the output something like this :

DataC
DataB

Notice that c’s text should be before b’s text

I think a xsl:sort needs be added to apply-templates , something like this:

<xsl:sort select='/root/section2/*[concat("#", @xml:id)=current()/@xlink:href][local-name()]' order="descending" />

i.e.:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:db="http://docbook.org/ns/docbook"
    xmlns:xlink="http://www.w3.org/1999/xlink">
    <xsl:output method="text"  indent="yes"/>
    <xsl:strip-space elements="*" />
    <xsl:preserve-space elements="db:para db:literallayout" />
    <xsl:param name="code" />
    <xsl:key name='mykeys' match='/root/section2/*' use='concat("#", @xml:id)'/>

    <xsl:template match="/" >
        <xsl:apply-templates select='/root/section1/a/ref'>
        </xsl:apply-templates>
    </xsl:template>

    <xsl:template match="ref">
        <xsl:apply-templates select='key("mykeys", @xlink:href)'  >
            <xsl:sort select='/root/section2/*[concat("#", @xml:id)=current()/@xlink:href][local-name()]'  order="descending" />
        </xsl:apply-templates>
    </xsl:template>

    <xsl:template match='b | c' >
        <xsl:value-of select="."  />
    </xsl:template>

</xsl:stylesheet>

But it doesn’t work. 

Notice that the ordering can’t be based on xml:id as it can be anything and it also cannot be based on the text (i.e. datac , datab , …) as they can be anything so the ordering should be based on Element Name ( i.e. , ) only.

I tried to understand what the actual value of select='/root/section2/*[concat("#", @xml:id)=current()/@xlink:href][local-name()]' is? so I sent it to the template as parameter:

 <xsl:template match="a">
   <xsl:apply-templates select='key("mykeys", @xlink:href)'  >
    <xsl:with-param name='testparameter' select='/root/section2/*[concat("#", @xml:id)=current()/@xlink:href][local-name()]'  />
   </xsl:apply-templates>
 </xsl:template>

<xsl:template match='b | c' >
    <xsl:param name='testparameter' />
    <xsl:value-of select='$testparameter' />
</xsl:template>

And surprising it was not the name of the element , if was the text of each element (i.e. DataB and DataC rather than b and c ) and even the order-type(descending) has not been applied as well.

Can you please help me and let me know how I can get an output like this:

DataC
DataB

Please notice that datac and datab should be accessible only via element and it means I can’t use

apply-templates select='/root/section2/b' or apply-templates select='/root/section2/c'

Thanks,

Это было полезно?

Решение

I think you need to put the xsl:sort in the apply-templates for the ref instead.

This seems to work...

<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xlink="http://www.w3.org/1999/xlink">
    <xsl:output method="text"  indent="yes"/>
    <xsl:strip-space elements="*" />
    <xsl:param name="code" />
    <xsl:key name='mykeys' match='/root/section2/*' use='concat("#", @xml:id)'/>

    <xsl:template match="/" >
        <xsl:apply-templates select='/root/section1/a/ref'>
            <xsl:sort select="local-name(key('mykeys', @xlink:href))" order="descending"/>
        </xsl:apply-templates>
    </xsl:template>

    <xsl:template match="ref">
        <xsl:apply-templates select='key("mykeys", @xlink:href)' />     
    </xsl:template>

    <xsl:template match='b | c' >
        <xsl:value-of select="."  />
    </xsl:template>

</xsl:stylesheet>

Also, using [local-name()] in this context is only checking to see if the element has a local name. I don't think this is what you intended.

If you want to use local-name() put your XPath as the argument to local-name() like: local-name(/some/xpath/*). (In XPath 2.0/XSLT 2.0 you could also put local-name() at the end of your path like: /some/xpath/*/local-name()

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top