У меня есть XML, как,

        <DESIGN-FUNCTION-PROTOTYPE>
          <SHORT-NAME>xxx</SHORT-NAME>
          <TYPE-TREF TYPE="DESIGN-FUNCTION-PROTOTYPE">ABC/DEF/123</TYPE-TREF>
        </DESIGN-FUNCTION-PROTOTYPE>
        <DESIGN-FUNCTION-PROTOTYPE>
          <SHORT-NAME>yyy</SHORT-NAME>
          <TYPE-TREF TYPE="DESIGN-FUNCTION-PROTOTYPE">LMN/OPQ/123</TYPE-TREF>
        </DESIGN-FUNCTION-PROTOTYPE>
        <DESIGN-FUNCTION-PROTOTYPE>
          <SHORT-NAME>mmm</SHORT-NAME>
          <TYPE-TREF TYPE="DESIGN-FUNCTION-PROTOTYPE">XYZ/GHY/456</TYPE-TREF>
        </DESIGN-FUNCTION-PROTOTYPE>
        <DESIGN-FUNCTION-PROTOTYPE>
          <SHORT-NAME>nnn</SHORT-NAME>
          <TYPE-TREF TYPE="DESIGN-FUNCTION-PROTOTYPE">AJK/UTL/456</TYPE-TREF>
        </DESIGN-FUNCTION-PROTOTYPE>

Мой xslt,

    <xsl:template name="substring-after-last">
    <xsl:param name="string" />
    <xsl:param name="delimiter" />
    <xsl:choose>
      <xsl:when test="contains($string, $delimiter)">
        <xsl:call-template name="substring-after-last">
          <xsl:with-param name="string"
            select="substring-after($string, $delimiter)" />
          <xsl:with-param name="delimiter" select="$delimiter" />
        </xsl:call-template>
      </xsl:when>
      <xsl:otherwise>
          <xsl:value-of select="$string" />
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

<xsl:for-each select="select="//DESIGN-FUNCTION-PROTOTYPE/ea:TYPE-TREF[@TYPE='DESIGN-FUNCTION-TYPE']">
      <xsl:variable name="myVar" select="current()"/>
      <xsl:variable name="taskName" select="../ea:SHORT-NAME"/>

         <xsl:variable name="Var7">    
         <xsl:call-template name="substring-after-last">
         <xsl:with-param name="string" select="$myVar" />
         <xsl:with-param name="delimiter" select="'/'" />
         </xsl:call-template>
         </xsl:variable>

         <varoutput> 
         <xsl:value-of select="$Var7"/>
         </varoutput>

</xsl:for-each>

Мое намерение здесь состоит в том, чтобы перебрать все элементы 'DESIGN-FUNCTION-PROTOTYPE' и отобразить подстроку значения 'TYPE-TREF', но если подстрока значения 'TYPE-TREF' уже была прочитана… i должен пропустить этот элемент.

Ожидаемый результат,

123
456

И нет,

123
123
456
456

В общем, я должен рассмотреть только первое появление и пропустить остальные.

0
Legolas 12 Апр 2019 в 18:19

2 ответа

Лучший ответ

Чтобы сделать это в чистом XSLT 1.0, не полагаясь на специфичные для процессора расширения, вы можете сделать:

XSLT 1.0

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

<xsl:key name="k1" match="DESIGN-FUNCTION-PROTOTYPE" use="substring-after(substring-after(TYPE-TREF, '/'), '/')"/>

<xsl:template match="/Root">
    <root>
        <xsl:for-each select="DESIGN-FUNCTION-PROTOTYPE[count(. | key('k1', substring-after(substring-after(TYPE-TREF, '/'), '/'))[1]) = 1]">
            <varoutput> 
                <xsl:value-of select="substring-after(substring-after(TYPE-TREF, '/'), '/')" />
            </varoutput> 
        </xsl:for-each>
    </root>  
</xsl:template>

</xsl:stylesheet>

Демо : https://xsltfiddle.liberty-development.net/bFN1y9s

Это, конечно, предполагает, что значение, которое вы ищете, всегда является третьим «токеном» в TYPE-TREF. В противном случае вам придется сделать что-то похожее на вашу попытку:

XSLT 1.0 + функция узла-набора () EXSLT

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:exsl="http://exslt.org/common"
exclude-result-prefixes="exsl" >
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>

<xsl:key name="k1" match="value" use="."/>

<xsl:template match="/Root">
    <!-- EXTRACT VALUES -->
    <xsl:variable name="values">
        <xsl:for-each select="DESIGN-FUNCTION-PROTOTYPE">
            <value> 
                 <xsl:call-template name="last-token">
                    <xsl:with-param name="text" select="TYPE-TREF"/>
                </xsl:call-template>
            </value> 
        </xsl:for-each>
    </xsl:variable>
    <!-- OUTPUT -->
    <root>
        <xsl:for-each select="exsl:node-set($values)/value[count(. | key('k1', .)[1]) = 1]">
            <varoutput> 
                <xsl:value-of select="." />
            </varoutput> 
        </xsl:for-each>
    </root>  
</xsl:template>

<xsl:template name="last-token">
    <xsl:param name="text"/>
    <xsl:param name="delimiter" select="'/'"/>
    <xsl:choose>
        <xsl:when test="contains($text, $delimiter)">
            <!-- recursive call -->
            <xsl:call-template name="last-token">
                <xsl:with-param name="text" select="substring-after($text, $delimiter)"/>
            </xsl:call-template>
        </xsl:when>
        <xsl:otherwise>
            <xsl:value-of select="$text"/>
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>

</xsl:stylesheet>

Демо : https://xsltfiddle.liberty-development.net/bFN1y9s / 1

1
michael.hor257k 13 Апр 2019 в 14:28

Если вы используете Xalan, у вас должен быть доступ к функции EXSLT str:split (http://xalan.apache.org/xalan-j/apidocs/org/apache/xalan/lib/ExsltStrings. HTML # раскол ( java.lang.String ,% 20java.lang.String ) :

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:str="http://exslt.org/strings" exclude-result-prefixes="str" version="1.0">

    <xsl:key name="group" match="DESIGN-FUNCTION-PROTOTYPE/TYPE-TREF"
        use="str:split(., '/')[last()]"/>

    <xsl:template match="Root">
        <xsl:for-each select="DESIGN-FUNCTION-PROTOTYPE/TYPE-TREF[generate-id() = generate-id(key('group', str:split(., '/')[last()])[1])]">
            <varoutput>
                <xsl:value-of select="str:split(., '/')[last()]"/>
            </varoutput>            
        </xsl:for-each>
    </xsl:template>

</xsl:stylesheet>

Трансформирует

<?xml version="1.0" encoding="UTF-8"?>
<Root>
    <DESIGN-FUNCTION-PROTOTYPE>
        <SHORT-NAME>xxx</SHORT-NAME>
        <TYPE-TREF TYPE="DESIGN-FUNCTION-PROTOTYPE">ABC/DEF/123</TYPE-TREF>
    </DESIGN-FUNCTION-PROTOTYPE>
    <DESIGN-FUNCTION-PROTOTYPE>
        <SHORT-NAME>yyy</SHORT-NAME>
        <TYPE-TREF TYPE="DESIGN-FUNCTION-PROTOTYPE">LMN/OPQ/123</TYPE-TREF>
    </DESIGN-FUNCTION-PROTOTYPE>
    <DESIGN-FUNCTION-PROTOTYPE>
        <SHORT-NAME>mmm</SHORT-NAME>
        <TYPE-TREF TYPE="DESIGN-FUNCTION-PROTOTYPE">XYZ/GHY/456</TYPE-TREF>
    </DESIGN-FUNCTION-PROTOTYPE>
    <DESIGN-FUNCTION-PROTOTYPE>
        <SHORT-NAME>nnn</SHORT-NAME>
        <TYPE-TREF TYPE="DESIGN-FUNCTION-PROTOTYPE">AJK/UTL/456</TYPE-TREF>
    </DESIGN-FUNCTION-PROTOTYPE>
</Root>

В

<?xml version="1.0" encoding="UTF-8"?><varoutput>123</varoutput><varoutput>456</varoutput>

С Xalan Java и Xalan Java XSLTC.

Или, как предлагается в комментарии, если вы просто хотите найти различные значения, вы можете использовать set:distinct, например

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:exsl="http://exslt.org/common"
    xmlns:str="http://exslt.org/strings"
    xmlns:set="http://exslt.org/sets"
    exclude-result-prefixes="exsl str set"
    version="1.0">

    <xsl:template match="Root">
        <xsl:variable name="split-values">
            <xsl:for-each select="DESIGN-FUNCTION-PROTOTYPE/TYPE-TREF">
                <xsl:copy-of select="str:split(., '/')[last()]"/>
            </xsl:for-each>        
        </xsl:variable>
        <xsl:copy-of select="set:distinct(exsl:node-set($split-values)/node())"/>
    </xsl:template>

</xsl:stylesheet>
1
Martin Honnen 13 Апр 2019 в 14:04