XSLT如何使用逗号分隔的String查找值?

时间:2013-01-31 16:35:21

标签: xml string xslt lookup comma

我想了解如何进行String查找以及如何分别解析逗号分隔的String。但是我想知道是否有一种有效的方法来满足这两个要求。这是我的源XML:

<?xml version="1.0" ?>
     <MATRIX>
     <DATA_RECORD>
      <COMPONENT1>1, 2</COMPONENT1> 
      <COMPONENT2>6, 7, 8, 9</COMPONENT2>  
     </DATA_RECORD>
    </MATRIX>

我希望通过解析逗号分隔的String并使用每个令牌进行查找来生成以下XML:

<?xml version="1.0" encoding="UTF-8"?>
     <MATRIX>
     <DATA_RECORD>
      <COMPONENT1>A, B</COMPONENT1> 
      <COMPONENT2>F, G, H, I</COMPONENT2>  
     </DATA_RECORD>
    </MATRIX>

这是我的查找XML(COMPONENT_LOOKUPLIST.xml):

<?xml version="1.0" ?>
    <MAIN>
      <DATA_RECORD>
        <COMPONENT_ID>1</COMPONENT_ID>
        <COMPONENT_NAME>A</COMPONENT_NAME>    
      </DATA_RECORD>
      <DATA_RECORD>
        <COMPONENT_ID>2</COMPONENT_ID>
        <COMPONENT_NAME>B</COMPONENT_NAME>    
      </DATA_RECORD>
        <DATA_RECORD>
        <COMPONENT_ID>3</COMPONENT_ID>
        <COMPONENT_NAME>C</COMPONENT_NAME>    
      </DATA_RECORD>
      <DATA_RECORD>
        <COMPONENT_ID>4</COMPONENT_ID>
        <COMPONENT_NAME>D</COMPONENT_NAME>    
      </DATA_RECORD>
        <DATA_RECORD>
        <COMPONENT_ID>5</COMPONENT_ID>
        <COMPONENT_NAME>E</COMPONENT_NAME>    
      </DATA_RECORD>
      <DATA_RECORD>
        <COMPONENT_ID>6</COMPONENT_ID>
        <COMPONENT_NAME>F</COMPONENT_NAME>    
      </DATA_RECORD>
        <DATA_RECORD>
        <COMPONENT_ID>7</COMPONENT_ID>
        <COMPONENT_NAME>G</COMPONENT_NAME>    
      </DATA_RECORD>
      <DATA_RECORD>
        <COMPONENT_ID>8</COMPONENT_ID>
        <COMPONENT_NAME>H</COMPONENT_NAME>    
      </DATA_RECORD>
      <DATA_RECORD>
        <COMPONENT_ID>9</COMPONENT_ID>
        <COMPONENT_NAME>I</COMPONENT_NAME>    
      </DATA_RECORD>
    </MAIN>

我是XSLT的初学者。一些XSLT专家可以分享一些想法或提供示例代码吗?我从Jeni的网站上获得了令牌代码:

 <xsl:template name="tokenize">
          <xsl:param name="string" />
          <xsl:param name="delimiter" select="','" />
          <xsl:choose>
            <xsl:when test="$delimiter and contains($string, $delimiter)">
              <token>
                <xsl:value-of select="substring-before($string, $delimiter)" />
              </token>

              <xsl:call-template name="tokenize">
                <xsl:with-param name="string" 
                                select="substring-after($string, $delimiter)" />
                <xsl:with-param name="delimiter" select="$delimiter" />
              </xsl:call-template>
            </xsl:when>

            <xsl:otherwise>
              <token><xsl:value-of select="$string" /></token>

            </xsl:otherwise>
          </xsl:choose>
        </xsl:template>

    <xsl:call-template name="tokenize">    
            <xsl:with-param name="string" select="/MATRIX/DATA_RECORD/COMPONENT1"></xsl:with-param>
          </xsl:call-template>

            <xsl:call-template name="tokenize">    
            <xsl:with-param name="string" select="/MATRIX/DATA_RECORD/COMPONENT2"></xsl:with-param>
          </xsl:call-template>

并写了一个查找:

<xsl:variable name="lookup" select="document('COMPONENT_LOOKUPLIST.xml')/MAIN/DATA_RECORD"/>
                <xsl:for-each select="//DATA_RECORD">

 <token>
  <xsl:for-each select="*">      
   <xsl:value-of select="$lookup[COMPONENT_ID = current()]/COMPONENT_NAME"/>        
          </xsl:for-each>   
          </token>
        </xsl:for-each>

但将这两者结合起来似乎很有挑战性。

谢谢。

2 个答案:

答案 0 :(得分:0)

您是否考虑使用像Saxon 9或AltovaXML或XmlPrime这样的XSLT 2.0处理器?在这种情况下,你可以很容易地做到。

<xsl:key name="by-id" match="DATA_RECORD" use="COMPONENT_ID"/>

<xsl:param name="lk-doc-url" select="'COMPONENT_LOOKUPLIST.xml'"/>
<xsl:variable name="lk-doc" select="document($lk-doc-url)"/>

<xsl:template match="*[starts-with(local-name(), 'COMPONENT')]">
  <xsl:copy>
    <xsl:value-of select="for $id in tokenize(., ', ') return key('by-id', $id, $lk-doc)/COMPONENT_NAME"
       separator=", "/>
  </xsl:copy>
</xsl:template>

[编辑] 这是一个完整且经过测试的样本:

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



<xsl:key name="by-id" match="DATA_RECORD" use="COMPONENT_ID"/>

<xsl:param name="lk-doc-url" select="'test2013013103.xml'"/>
<xsl:variable name="lk-doc" select="document($lk-doc-url)"/>

<xsl:template match="@* | node()">
  <xsl:copy>
    <xsl:apply-templates select="@* , node()"/>
  </xsl:copy>
</xsl:template>

<xsl:template match="*[starts-with(local-name(), 'COMPONENT')]">
  <xsl:copy>
    <xsl:value-of select="for $id in tokenize(., ', ') return key('by-id', $id, $lk-doc)/COMPONENT_NAME"
       separator=", "/>
  </xsl:copy>
</xsl:template>

</xsl:stylesheet>

当我将Saxon 9.4应用于输入

<?xml version="1.0" ?>
     <MATRIX>
     <DATA_RECORD>
      <COMPONENT1>1, 2</COMPONENT1> 
      <COMPONENT2>6, 7, 8, 9</COMPONENT2>  
     </DATA_RECORD>
    </MATRIX>
查找文件test2013013103.xml

<?xml version="1.0" ?>
    <MAIN>
      <DATA_RECORD>
        <COMPONENT_ID>1</COMPONENT_ID>
        <COMPONENT_NAME>A</COMPONENT_NAME>    
      </DATA_RECORD>
      <DATA_RECORD>
        <COMPONENT_ID>2</COMPONENT_ID>
        <COMPONENT_NAME>B</COMPONENT_NAME>    
      </DATA_RECORD>
        <DATA_RECORD>
        <COMPONENT_ID>3</COMPONENT_ID>
        <COMPONENT_NAME>C</COMPONENT_NAME>    
      </DATA_RECORD>
      <DATA_RECORD>
        <COMPONENT_ID>4</COMPONENT_ID>
        <COMPONENT_NAME>D</COMPONENT_NAME>    
      </DATA_RECORD>
        <DATA_RECORD>
        <COMPONENT_ID>5</COMPONENT_ID>
        <COMPONENT_NAME>E</COMPONENT_NAME>    
      </DATA_RECORD>
      <DATA_RECORD>
        <COMPONENT_ID>6</COMPONENT_ID>
        <COMPONENT_NAME>F</COMPONENT_NAME>    
      </DATA_RECORD>
        <DATA_RECORD>
        <COMPONENT_ID>7</COMPONENT_ID>
        <COMPONENT_NAME>G</COMPONENT_NAME>    
      </DATA_RECORD>
      <DATA_RECORD>
        <COMPONENT_ID>8</COMPONENT_ID>
        <COMPONENT_NAME>H</COMPONENT_NAME>    
      </DATA_RECORD>
      <DATA_RECORD>
        <COMPONENT_ID>9</COMPONENT_ID>
        <COMPONENT_NAME>I</COMPONENT_NAME>    
      </DATA_RECORD>
    </MAIN>

输出

<?xml version="1.0" encoding="UTF-8"?><MATRIX>
     <DATA_RECORD>
      <COMPONENT1>A, B</COMPONENT1>
      <COMPONENT2>F, G, H, I</COMPONENT2>
     </DATA_RECORD>
    </MATRIX>

所以我的建议有效,我不确定你的情况有什么不同,你没有得到任何内容。

答案 1 :(得分:0)

如果您遇到XSLT1.0,一个解决方案可能是修改 tokenize 模板进行查找,而不是吐出令牌元素(如果你保留了标记元素,你必须进行两遍变换,根据你的查找将它们转换回字符串。

所以,而不是在 tokenize 模板中执行此操作

<token>
   <xsl:value-of select="substring-before($string, $delimiter)" />
</token>

这样做,而不是

<xsl:value-of select="$lookup[COMPONENT_ID=normalize-space(substring-before($string, $delimiter))]/COMPONENT_NAME"/>
 <xsl:value-of select="$delimiter"/>

这是完整的XSLT

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
   <xsl:output omit-xml-declaration="yes" method="html"/>

   <xsl:variable name="lookup" select="document('C:\COMPONENT_LOOKUPLIST.xml')/MAIN/DATA_RECORD"/>

   <xsl:template match="DATA_RECORD/*">
      <xsl:copy>
         <xsl:call-template name="tokenize">
            <xsl:with-param name="string" select="."/>
         </xsl:call-template>
      </xsl:copy>
   </xsl:template>

   <xsl:template match="@*|node()">
      <xsl:copy>
         <xsl:apply-templates select="@*|node()"/>
      </xsl:copy>
   </xsl:template>

   <xsl:template name="tokenize">
      <xsl:param name="string"/>
      <xsl:param name="delimiter" select="','"/>
      <xsl:choose>
         <xsl:when test="$delimiter and contains($string, $delimiter)">
            <xsl:value-of select="$lookup[COMPONENT_ID=normalize-space(substring-before($string, $delimiter))]/COMPONENT_NAME"/>
            <xsl:value-of select="$delimiter"/>
            <xsl:call-template name="tokenize">
               <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="$lookup[COMPONENT_ID=normalize-space($string)]/COMPONENT_NAME"/>
         </xsl:otherwise>
      </xsl:choose>
   </xsl:template>
</xsl:stylesheet>

应用于XML时,输出以下内容

<MATRIX>
   <DATA_RECORD>
      <COMPONENT1>A,B</COMPONENT1>
      <COMPONENT2>F,G,H,I</COMPONENT2>
   </DATA_RECORD>
</MATRIX>

注意,这确实会删除空格,但希望这不是问题...

编辑:如果你想保留空格,你可以这样做:

<xsl:variable name="current" select="substring-before($string, $delimiter)" />
<xsl:value-of select="substring-before($current, normalize-space($current))" /> 
<xsl:value-of select="$lookup[COMPONENT_ID=normalize-space($)]/COMPONENT_NAME"/>
<xsl:value-of select="substring-after($current, normalize-space($current))" />