English 中文(简体)
How to extract unique characters from a string using XSLT 1.0?
原标题:

one of the toughest challenges I have ever faced in XSLT designing ..

How to copy the unique characters in a given string ..
Test xml is:

<root>
<string>aaeerstrst11232434</string>
</root>

The output I am expecting is:

<string>aerst1234</string>
最佳回答

Here is an XSLT 1.0 solution, shorter than the currently selected answer and easier to write as it uses the str-foldl template of FXSL.

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:f="http://fxsl.sf.net/"
 exclude-result-prefixes="f">

 <xsl:import href="str-foldl.xsl"/>
 <xsl:output method="text"/>

 <f:addUnique/>

 <xsl:variable name="vFunAddunique" select=
  "document(  )/*/f:addUnique[1]
  "/>

    <xsl:template match="string">
      <xsl:call-template name="str-foldl">
        <xsl:with-param name="pFunc" select="$vFunAddunique"/>
        <xsl:with-param name="pA0" select="  "/>
        <xsl:with-param name="pStr" select="."/>
      </xsl:call-template>
    </xsl:template>

    <xsl:template match="f:addUnique" mode="f:FXSL">
      <xsl:param name="arg1"/>
      <xsl:param name="arg2"/>

      <xsl:value-of select="$arg1"/>
      <xsl:if test="not(contains($arg1, $arg2))">
       <xsl:value-of select="$arg2"/>
      </xsl:if>
    </xsl:template>
</xsl:stylesheet>

When the above transformation is applied to the originally provided source XML document:

<root>
    <string>aaeerstrst11232434</string>
</root>

the wanted result is produced:

aerst1234

Read more about FXSL 1.x (for XSLT 1.0) here, and about FXSL 2.x (for XSLT 2.0) here.

问题回答

Use the following XPath one-liner:

codepoints-to-string(distinct-values(string-to-codepoints(.)))

A complete transformation using this is below:

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

    <xsl:template match="string">
      <xsl:value-of select=
      "codepoints-to-string(distinct-values(string-to-codepoints(.)))
      "/>
    </xsl:template>
</xsl:stylesheet>

When this transformation is applied on the originally provided XML document:

<root>
    <string>aaeerstrst11232434</string>
</root>

the wanted result is produced:

aerst1234

In case an XSLT 1.0 solution is needed -- please, indicate so and I ll provide it.

Here is an XSLT 1.0 solution:

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

  <xsl:strip-space elements="*"/>
  <xsl:output method="text"/>

  <xsl:template match="string">
    <xsl:call-template name="unique">
      <xsl:with-param name="input" select="."/>
    </xsl:call-template>
  </xsl:template>

  <xsl:template name="unique">
    <xsl:param name="input"/>
    <xsl:param name="output" select="  "/>
    <xsl:variable name="c" select="substring($input, 1, 1)"/>
    <xsl:choose>
      <xsl:when test="not($input)">
        <xsl:value-of select="$output"/>
      </xsl:when>
      <xsl:when test="contains($output, $c)">
        <xsl:call-template name="unique">
          <xsl:with-param name="input" select="substring($input, 2)"/>
          <xsl:with-param name="output" select="$output"/>
        </xsl:call-template>
      </xsl:when>
      <xsl:otherwise>
        <xsl:call-template name="unique">
          <xsl:with-param name="input" select="substring($input, 2)"/>
          <xsl:with-param name="output" select="concat($output, $c)"/>
        </xsl:call-template>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

</xsl:stylesheet>

When I tried with a more complicated XML, then I encountered many problems with Martin Honnen s solution, it doesn t work with the below mentioned XML, so I prepared my own solution refering to Dimitre s this answer And also I could call it a more efficient solution:

Here is an input xml:

    <root>
      <string>aabcdbcd1abcdefghijklmanopqrstuvwxyzabcdefgh0123456789ijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz12312489796453134049446798421230156489413210315487804210313264046040489789789745648974321231564648971232344</string>
      <string2>oejrinsjfojofjweofj24798273492jfakjflsdjljk</string2>
    </root>

And here is the Working XSLT code:

  <xsl:template match="@* | node()">
    <xsl:copy>
      <xsl:apply-templates select="@* | node()"/>
    </xsl:copy>
  </xsl:template>
  <xsl:template match="text()">
    <xsl:call-template name="unique_chars">
      <xsl:with-param name="input" select="."/>
    </xsl:call-template>
  </xsl:template>

  <xsl:template name="unique_chars">
    <xsl:param name="input"/>
    <xsl:variable name="c">
      <xsl:value-of select="substring($input, 1, 1)"/>
    </xsl:variable>
    <xsl:choose>
      <xsl:when test="not($input)"/>
      <xsl:otherwise>
        <xsl:choose>
          <xsl:when test="contains(substring($input, 2), $c)">
            <xsl:call-template name="unique_chars">
              <xsl:with-param name="input" select="substring($input, 2)"/>
            </xsl:call-template>
          </xsl:when>
          <xsl:otherwise>
            <xsl:value-of select="$c"/>
            <xsl:call-template name="unique_chars">
              <xsl:with-param name="input" select="substring($input, 2)"/>
            </xsl:call-template>
          </xsl:otherwise>
        </xsl:choose>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>
</xsl:stylesheet>




相关问题
how to represent it in dtd?

I have two element action and guid. guid is a required field when action is add. but when action is del it will not appear in file. How to represent this in dtd ?

.Net application configuration add xml-data

I need to add xml-content to my application configuration file. Is there a way to add it directly to the appSettings section or do I need to implement a configSection? Is it possible to add the xml ...

XStream serializing collections

I have a class structure that I would like to serialize with Xstream. The root class contains a collection of other objects (of varying types). I would like to only serialize part of the objects that ...

MS Word splits words in its XML format

I have a Word 2003 document saved as a XML in WordProcessingML format. It contains few placeholders which will be dynamically replaced by an appropriate content. But, the problem is that Word ...

Merging an XML file with a list of changes

I have two XML files that are generated by another application I have no control over. The first is a settings file, and the second is a list of changes that should be applied to the first. Main ...

How do I check if a node has no siblings?

I have a org.w3c.dom.Node object. I would like to see if it has any other siblings. Here s what I have tried: Node sibling = node.getNextSibling(); if(sibling == null) return true; else ...

Ordering a hash to xml: Rails

I m building an xml document from a hash. The xml attributes need to be in order. How can this be accomplished? hash.to_xml

热门标签