首页 文章

XSLT选择节点,其中元素值的子串不等于其他节点的元素值

提问于
浏览
0

我是CSS新手,遇到了障碍 . 我有一个图像详细信息列表,如下所示 .

<Files IsList="true">
  <Item>
    <FileSize>97 kb</FileSize>
    <Type>image/jpeg</Type>
    <Name>CR_0_Pc_7vxsysv.jpg</Name>
    <Description>Picture</Description>
  </Item>
  <Item>
    <FileSize>108 kb</FileSize>
    <Type>image/jpeg</Type>
    <Name>CR_0_Pc_9cxjbh7.jpg</Name>
    <Description>Picture</Description>
  </Item>
  <Item>
    <FileSize>109 kb</FileSize>
    <Type>image/jpeg</Type>
    <Name>CR_0_Pc_9cxjbh7_Annotated.jpg</Name>
    <Description>(annotated)</Description>
  </Item>
  <Item>
    <FileSize>170 kb</FileSize>
    <Type>image/jpeg</Type>
    <Name>CR_0_Pc_omau6bn.jpg</Name>
    <Description>Picture</Description>
  </Item>
  <Item>
    <FileSize>175 kb</FileSize>
    <Type>image/jpeg</Type>
    <Name>CR_0_Pc_omau6bn_Annotated.jpg</Name>
    <Description>(annotated)</Description>
  </Item>
</Files>

所有图像都有一个原始文件,一些图像有一个带注释的副本(由描述和名称后缀标识) .

我需要显示所有图像(在一个表中有3个图像到一行),逻辑:

  • 如果有带注释的副本,则仅显示带注释的版本

  • 如果没有带注释的副本显示原件 .

Desired Outcome是一个选择语句,产生以下结果 .

<Item>
    <FileSize>97 kb</FileSize>
    <Type>image/jpeg</Type>
    <Name>CR_0_Pc_7vxsysv.jpg</Name>
    <Description>Picture</Description>
  </Item>
  <Item>
    <FileSize>109 kb</FileSize>
    <Type>image/jpeg</Type>
    <Name>CR_0_Pc_9cxjbh7_Annotated.jpg</Name>
    <Description>(annotated)</Description>
  </Item>
  <Item>
    <FileSize>175 kb</FileSize>
    <Type>image/jpeg</Type>
    <Name>CR_0_Pc_omau6bn_Annotated.jpg</Name>
    <Description>(annotated)</Description>
  </Item>

我试图循环遍历所有节点并使用IF语句来确定是否显示了哪些节点,但是因为我使用position()来确定从哪一个开始新行,这不起作用,因为并非所有图像都显示出来,抛弃了行计算 .

我认为select需要基于Name元素值的子字符串,并与其他Name元素的子字符串进行比较 .

这可能吗?

2 回答

  • 0

    如果有带注释的副本,则仅显示带注释的版本如果没有带注释的副本则显示原始版本 . Desired Outcome是一个选择语句,产生以下结果 .

    您可以使用以下表达式选择所请求的项目:

    select="Item[Description='(annotated)' or not(key('anno', substring(Name, 1, 15)))]"/>
    

    定义一个键之后:

    <xsl:key name="anno" match="Item[Description='(annotated)']" use="substring(Name, 1, 15)" />
    

    这假设所有项目名称都是15个字符长 . 如果这个假设不正确,那么它会变得更复杂 .


    请注意,仅选择项目是不够的,因为所选项目保持其原始上下文 . 为了使选定的项目成为兄弟姐妹,你需要将它们变成一个变量 . 以下是完整样式表的示例,将所选项目分为三列:

    XSLT 1.0

    <xsl:stylesheet version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:exsl="http://exslt.org/common"
    extension-element-prefixes="exsl">
    <xsl:output method="html" encoding="utf-8"/>
    
    <xsl:key name="anno" match="Item[Description='(annotated)']" use="substring(Name, 1, 15)" />
    
    <xsl:template match="/Files">
        <xsl:variable name="items">
            <xsl:copy-of select="Item[Description='(annotated)' or not(key('anno', substring(Name, 1, 15)))]"/>
        </xsl:variable>
        <xsl:variable name="cols" select="3" />
        <table border="1">
            <xsl:for-each select="exsl:node-set($items)/Item[position() mod $cols = 1]" >
            <tr>
                <xsl:apply-templates select=". | following-sibling::Item[position() &lt; $cols]"/>
            </tr>
            </xsl:for-each>
        </table>
    </xsl:template>
    
    <xsl:template match="Item">
        <td><img src="{Name}"/></td>
    </xsl:template>
    
    </xsl:stylesheet>
    
  • 0

    我不知道你是否想要XSLT 1.0或XSLT 2.0,并且你不想要一个html表输出或xml输出(你似乎在这方面自相矛盾),所以这可能不完全符合你的要求,但它可能会有所帮助 .

    这个XSLT 2.0样式表......

    <xsl:transform
        xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        version="2.0">
    
    <xsl:output method="html" version="5" encoding="UTF-8" indent="yes" />
    <xsl:strip-space elements="*" />
    
    
    <xsl:template match="/">
      <hmtl>
        <head>
          <title>Table of items</title>
        </head>
        <body>
          <table>
            <tbody>
              <xsl:for-each-group
                  select="Files/Item[
                    (Description eq '(annotated)') or
                     not(
                       for $name in concat( substring-before( Name/text(), '.jpg'), '_Annotated.jpg') return
                         following-sibling::Item[ Name eq $name])]"
                  group-by="(position() - 1) idiv 3">
                <tr>
                  <xsl:apply-templates select="current-group()" />
                </tr>
              </xsl:for-each-group>
            </tbody>
          </table>
        </body>
      </hmtl>
    </xsl:template>
    
    <xsl:template match="Item">
      <td>
        <xsl:copy-of select="." />
      </td>
    </xsl:template>
    
    </xsl:transform>
    

    ...将改变这个输入文件......

    <Files IsList="true">
      <Item>
        <FileSize>97 kb</FileSize>
        <Type>image/jpeg</Type>
        <Name>CR_0_Pc_7vxsysv.jpg</Name>
        <Description>Picture</Description>
      </Item>
      <Item>
        <FileSize>108 kb</FileSize>
        <Type>image/jpeg</Type>
        <Name>CR_0_Pc_9cxjbh7.jpg</Name>
        <Description>Picture</Description>
      </Item>
      <Item>
        <FileSize>109 kb</FileSize>
        <Type>image/jpeg</Type>
        <Name>CR_0_Pc_9cxjbh7_Annotated.jpg</Name>
        <Description>(annotated)</Description>
      </Item>
      <Item>
        <FileSize>170 kb</FileSize>
        <Type>image/jpeg</Type>
        <Name>CR_0_Pc_omau6bn.jpg</Name>
        <Description>Picture</Description>
      </Item>
      <Item>
        <FileSize>175 kb</FileSize>
        <Type>image/jpeg</Type>
        <Name>CR_0_Pc_omau6bn_Annotated.jpg</Name>
        <Description>(annotated)</Description>
      </Item>
    </Files>
    

    ...进入这个输出html页面......

    <!DOCTYPE HTML>
    <hmtl>
       <head>
          <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
          <title>Table of items</title>
       </head>
       <body>
          <table>
             <tbody>
                <tr>
                   <td>
                      <Item>
                         <FileSize>97 kb</FileSize>
                         <Type>image/jpeg</Type>
                         <Name>CR_0_Pc_7vxsysv.jpg</Name>
                         <Description>Picture</Description>
                      </Item>
                   </td>
                   <td>
                      <Item>
                         <FileSize>109 kb</FileSize>
                         <Type>image/jpeg</Type>
                         <Name>CR_0_Pc_9cxjbh7_Annotated.jpg</Name>
                         <Description>(annotated)</Description>
                      </Item>
                   </td>
                   <td>
                      <Item>
                         <FileSize>175 kb</FileSize>
                         <Type>image/jpeg</Type>
                         <Name>CR_0_Pc_omau6bn_Annotated.jpg</Name>
                         <Description>(annotated)</Description>
                      </Item>
                   </td>
                </tr>
             </tbody>
          </table>
       </body>
    </hmtl>
    

    设计说明

    分组( xsl:for-each-group )实际上只是将输出编组到3列表中 . table 粗糙 . 如果您需要常规表来支持旧版浏览器,则需要在最后一行添加一些额外代码 .

    这是你在关闭 </tr> 之前添加的内容,以使其成为常规

    <xsl:for-each select="1 to 3 - count(current-group())">
      <td>&#160;</td>
    </xsl:for-each>
    

    xsl:for-each-group/@select 中的XPath表达式为此解决方案带来了沉重的负担 . 它选择所有 Item 元素,这些元素要么带注释,要么没有匹配的带注释的兄弟 . 这基本上是您要处理输出的内容 .


    更新

    这是一个等效的XSLT 1.0解决方案..

    <xsl:transform
        xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        xmlns:exsl="http://exslt.org/common"
        extension-element-prefixes="exsl"
        version="1.0">
    
    <xsl:output method="html" doctype-system="" encoding="UTF-8" indent="yes" />
    <xsl:strip-space elements="*" />    
    
    <xsl:template match="/">
      <hmtl>
        <head>
          <title>Table of items</title>
        </head>
        <body>
          <table>
            <tbody>
              <xsl:variable name="Items">
                <xsl:apply-templates select="Files/Item" mode="filter-items" />
              </xsl:variable>
              <xsl:apply-templates select="exsl:node-set($Items)/Item" mode="row" />
            </tbody>
          </table>
        </body>
      </hmtl>
    </xsl:template>
    
    <xsl:template match="Item[Description='(annotated)']" mode="filter-items">
      <xsl:copy-of select="." />
    </xsl:template>
    
    <xsl:template match="Item[Description!='(annotated)']" mode="filter-items">
      <xsl:variable name="name" select="concat( substring-before( Name/text(), '.jpg'), '_Annotated.jpg')" />
      <xsl:if test="not( following-sibling::Item[ Name = $name])">
        <xsl:copy-of select="." />
      </xsl:if>
    </xsl:template>
    
    <xsl:template match="Item[1]" mode="row">
      <tr>
        <xsl:apply-templates select=". | following-sibling::Item[position() &lt;= 2]" mode="cell" />
        <xsl:variable name="empty-cols" select=" 3 - count(. | following-sibling::Item[position() &lt;= 2])" />
        <xsl:for-each select="(//node())[position() &lt;= $empty-cols]">
          <td>&#160;</td>
        </xsl:for-each>
      </tr>    
    </xsl:template>
    
    <xsl:template match="Item" mode="row" />
    
    <xsl:template match="Item" mode="cell">
      <td>
        <xsl:copy-of select="." />
      </td>    
    </xsl:template>
    
    </xsl:transform>
    

    以上假设您的XSLT 1.0引擎支持exslt . 请注意,没有理由不升级到XSLT 2.0 . 如果您的平台是浏览器,那么您可以使用Saxon CE来实现升级 . 使用the Piez method使输出表成为常规 . 如果效率太低,还有其他选择 .

相关问题