XSLT查找一个列表中不在另一个列表中的所有节点

时间:2011-01-13 20:43:54

标签: xslt compare

我有xml,essentialy如下所示(我的实际.xml是包含VStudio和DotCover构建输出的联合的构建日志):

<buildlog>
  <Projects>
    <project name="project1.csproj" />
    <project name="project2.csproj" />
    <project name="project3.csproj" />
    <project name="project4.csproj" />
  </Projects>
  <Root>
    <Assembly Name="project1" />
    <Assembly Name="project2" />
  </Root>
</buildlog>

我需要一个列表,列出在Root / Assembly节点集中@Name上没有相应@name匹配的所有项目节点。我的目标是生成一个报告,显示所有没有代码覆盖率的项目。

这是我的xsl样式表的开头:

    <xsl:template match="/">
        <xsl:apply-templates select="buildlog/Projects" />
      </xsl:template>

      <xsl:template match="Projects">

        <table>
          <tr>
             <td>Assemblies Not Covered:</td>
             <td><xsl:value-of select="count(./project)"/></td>
          </tr>
        </table>

        <xsl:apply-templates select="project" />

      </xsl:template>

      <xsl:template match="project">

        <table>
          <tr>
            <td style="padding-left:30px">
              <xsl:value-of select="substring-before(./@name,'.csproj')"/>
            </td>
          </tr>
        </table>

      </xsl:template>

提前致谢。

临时解决方案

目前我使用ms:脚本扩展解决了我的问题。下面是代码。 不是最优雅的,它只是一个Windows解决方案,但它解决了这个问题。生病 其他人推荐的内容,并在评论部分回答。

Here's my solution:

<xsl:stylesheet version="1.0"
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns="http://www.w3.org/TR/xhtml1/strict"
                xmlns:ms="urn:schemas-microsoft-com:xslt"
                xmlns:dsi="urn:dsi-scripts">
  <xsl:output method="html"/>

  <xsl:template match="/">

    <xsl:apply-templates select="buildlog/Projects" />


  </xsl:template>

  <xsl:template match="Projects">
    <table>
      <tr>
        <td>Assemblies Not Covered:</td>
      </tr>
    </table>

    <xsl:apply-templates select="project" />

  </xsl:template>

  <xsl:template match="project">
    <xsl:variable name="assemblies" select="//Assembly" />

    <xsl:if test="not(dsi:HasCoverage($assemblies/@Name, ./@name))">
      <table>
        <tr>
          <td style="padding-left:30px">
            <xsl:value-of select="substring-before(./@name,'.csproj')"/>
          </td>
        </tr>
      </table>
    </xsl:if>

  </xsl:template>

  <xsl:template match="Assembly">
    <table>
      <tr>
        <td style="padding-left:30px">
          <xsl:value-of select="@Name"/>
        </td>
      </tr>
    </table>
  </xsl:template>

  <ms:script language="C#" implements-prefix="dsi">
    <![CDATA[
      public bool HasCoverage(XPathNodeIterator assemblies, string project)
      {
        bool result = false;
        while(assemblies.MoveNext())
        {
          if(assemblies.Current.Value == project.Replace(".csproj",string.Empty))
          {
            result = true;
            break;
          }
        }
        return result;
      }

    ]]>
  </ms:script>

</xsl:stylesheet>

1 个答案:

答案 0 :(得分:3)

  

我需要一个包含所有项目节点的列表   没有相应的@name   匹配@中的@Name   根/程序集节点

使用

/*/Projects/project
     [not(substring-before(@name, '.csproj') = /*/Root/Assembly/@Name)]

此XPath表达式精确选择所需的project元素。

完整解决方案

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:template match=
    "Projects/project
        [not(substring-before(@name, '.csproj')
        =
         /*/Root/Assembly/@Name)] ">
  <xsl:value-of select="concat(@name,'&#xA;')"/>
 </xsl:template>

</xsl:stylesheet>

将此转换应用于提供的XML文档

<buildlog>
    <Projects>
        <project name="project1.csproj" />
        <project name="project2.csproj" />
        <project name="project3.csproj" />
        <project name="project4.csproj" />
    </Projects>
    <Root>
        <Assembly Name="project1" />
        <Assembly Name="project2" />
    </Root>
</buildlog>

生成了想要的结果

project3.csproj
project4.csproj

如果确实需要更高的效率,则应使用密钥。