开发者

XSL unique values per node per position

this get ever more complicated :)

now i face another issue in last question we managed to take unique values from only one parent node

now with:

<?xml version="1.0" encoding="ISO-8859-1"?>
<roots>
     <root>
          <name>first</name>
          <item>
               <something>A</something>
               <something>A</something>
          </item>
          <item>
               <something>B</something>
               <something>A</something>
          </item>
          <item>
               <something>C</something>
               <something>P</something>
          </item>
          <item>
               <something>A</something>
               <something>L</something>
          </item>
          <item>
               <something>A</something>
               <something>A</something>
          </item>
          <item>
               <something>B</something>
               <something>A</something>
          </item>
          <item>
               <something>D</something>
               <something>A</something>
          </item>
     </root>
     <root>
          <name>second</name>
          <item>
               <something>E</something>
               <something>A</something>
          </item>
          <item>
               <something>B</something>
               <something>A</something>
          </item>
          <item>
               <something>F</something>
               <something>A</something>
          </item>
          <item>
               <something>A</something>
               <something>A</something>
          </item>
          <item>
               <something>A</something>
               <something>A</something>
          </item>
          开发者_运维百科<item>
               <something>B</something>
               <something>H</something>
          </item>
          <item>
               <something>D</something>
               <something>G</something>
          </item>
     </root>
</roots>

now i need to get the unique values depending only from one node before but just from the elements on the second position

  <?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

  <xsl:output indent="yes" method="text"/>
  <xsl:key name="item-by-value" match="something"
 use="concat(normalize-space(.), ' ', generate-id(./ancestor::root))"/>
<xsl:key name="rootkey" match="root" use="name"/>
  <xsl:template match="/">
 <xsl:for-each select="key('rootkey','first')">
<xsl:for-each select="item/something[1]">
<xsl:sort />
  <xsl:if test="generate-id() = generate-id(key('item-by-value', 
                  concat(normalize-space(.), ' ', generate-id(./ancestor::root))))">
  <xsl:value-of select="."/>
 </xsl:if>
</xsl:for-each> 
<xsl:text>_________</xsl:text>
<xsl:for-each select="item/something[2]">
<xsl:sort />
  <xsl:if test="generate-id() = generate-id(key('item-by-value', 
                  concat(normalize-space(.), ' ', generate-id(./ancestor::root))))">
  <xsl:value-of select="."/>
 </xsl:if>
</xsl:for-each> 
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>

with this XSL i get ABCD_________LP where the result i need is ABCD_________ALP

any ideas?


Once again, the issue is that if you want to say "the first node with this content under this root appearing in this position in the item node", then you have to add "position in the item node" to the key. You can either do this by having two separate keys, as Dimitre's solution does, or change your key to:

use="concat(normalize-space(.), ' ', 
     count(./preceding-sibling::something), ' ', generate-id(./ancestor::root))"/>

And then make your two test expressions look like:

<xsl:if test="generate-id() = generate-id(key('item-by-value', 
              concat(normalize-space(.), ' 0 ', generate-id(./ancestor::root))))">

and:

<xsl:if test="generate-id() = generate-id(key('item-by-value', 
              concat(normalize-space(.), ' 1 ', generate-id(./ancestor::root))))">


Just a slight modification to my answer to your previous question and you've got it!

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

 <xsl:key name="kSomethingByNameAndVal-1" match="something[1]"
  use="concat(../../name, '+', .)"/>

 <xsl:key name="kSomethingByNameAndVal-2" match="something[2]"
  use="concat(../../name, '+', .)"/>

 <xsl:template match="/">
   <xsl:for-each select="*/*">
     <xsl:for-each select=
      "item/something[1]
             [generate-id()
             =
              generate-id(key('kSomethingByNameAndVal-1',
                               concat(../../name, '+', .)
                              )
                          )
             ]
      ">

       <xsl:value-of select="."/>
     </xsl:for-each>
     <xsl:text>&#xA;</xsl:text>

     <xsl:for-each select=
      "item/something[2]
             [generate-id()
             =
              generate-id(key('kSomethingByNameAndVal-2',
                               concat(../../name, '+', .)
                              )
                          )
             ]
      ">

       <xsl:value-of select="."/>
     </xsl:for-each>
     <xsl:text>&#xA;</xsl:text>
   </xsl:for-each>
 </xsl:template>
</xsl:stylesheet>

When this transformation is applied on the provided XML document, The wanted, correct results are produced:

ABCD
APL
EBFAD
AHG


I know you're restricted to XSLT 1.0 and you're using Xalan, but I'm going to add this answer just in case it might help someone else doing a search in the future. (That can use XSLT 2.0.) Hope you don't mind.

Also, I'm using Saxon-HE 9.2.0.6 for the processor.

Here's the stylesheet:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
   <xsl:output method="text"/>

   <xsl:template match="/roots">
      <xsl:for-each select="root">
         <xsl:value-of select="distinct-values(item/something[1])"/>___<xsl:value-of select="distinct-values(item/something[2])"/>
         <xsl:text>&#xA;</xsl:text>
      </xsl:for-each>
   </xsl:template>

</xsl:stylesheet>

Here's the output using your XML:

A B C D___A P L
E B F A D___A H G

If you wanted to strip the spaces from the output, you could put the output in a variable and then use replace to strip the spaces. (Anyone know of a better way?)

Stylesheet:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
   <xsl:output method="text"/>

   <xsl:template match="/roots">
      <xsl:variable name="output">
         <xsl:for-each select="root">
            <xsl:value-of select="distinct-values(item/something[1])"/>___<xsl:value-of select="distinct-values(item/something[2])"/>
            <xsl:text>&#xA;</xsl:text>
         </xsl:for-each>
      </xsl:variable>
      <xsl:value-of select="replace($output,' ','')"/>
   </xsl:template>

</xsl:stylesheet>

Output:

ABCD___APL
EBFAD___AHG
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜