Как выбрать дочерние узлы, которые не имеют определенного родителя в качестве предка? - PullRequest
2 голосов
/ 29 июня 2010

Мы используем CruiseControl для нашего сервера сборки.Он компилирует наши приложения с использованием MSBuild и использует собственный XML-регистратор, который выдает что-то вроде следующего XML:

<project name="CI">
  <target name="CompileApp">
    <project name="Project1.csproj">
      <target name="build">
        <error>Compilation error one!</error>
      </target>
      <target name="BeforeBuild">
        <project name="Project2.csproj">
          <target name="build">
            <error>Compilation error two!</error>
          </target>
        </project>
      </target>
    </project>
  </target>
</project>

Я хочу преобразовать это в отчет, который выводит ошибки каждого проекта.Я не хочу сообщать об ошибках в других проектах.

  Project "Project1.csproj": 1 error(s)
  Error(s):  
  Compilation error one!

  Project "Project2.csproj": 1 error(s)
  Error(s):
  Compilation error two!

Это самое близкое, что я получил, но это не правильно.Он не отфильтровывает ошибки project2 при отображении ошибок project1.

<xsl:template>
  <xsl:variable select="//project[.//error]" name="projects.with.errors" />
  <xsl:apply-templates select="$projects.with.errors" />
</xsl:template>

<xsl:template match="project">
   <xsl:variable select="./*[not(project)]//error" name="errors" />
   <xsl:if test="count($errors) > 1">
      <!-- display errors -->
   </xsl:if>
</xsl:template>

Как отфильтровать все узлы ошибок, у которых есть предок проекта, отличный от моего текущего узла проекта?Т.е. как я могу выбрать только потомки с ошибочными узлами, у которых нет предка проекта?

Узлы с ошибками могут иметь произвольное количество родительских элементов (обычно, но не всегда).

Ответы [ 3 ]

2 голосов
/ 29 июня 2010

Это преобразование :

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output method="text"/>
 <xsl:strip-space elements="*"/>

 <xsl:key name="kProjectByName" match="project"
  use="@name"/>

 <xsl:key name="kErrByProject" match="error"
  use="ancestor::project[1]/@name"/>

 <xsl:template match="/">
   <xsl:for-each select=
    "//project
          [generate-id()
          =
           generate-id(key('kProjectByName', @name)[1])
           ]
    ">
     <xsl:variable name="vErrors" select=
       "key('kErrByProject', @name)"/>

     <xsl:if test="$vErrors">
         Project <xsl:value-of select="@name"/><xsl:text>: </xsl:text>
         <xsl:value-of select="count($vErrors)"/> errors.
         Errors:
         <xsl:for-each select="$vErrors">
           <xsl:value-of select="."/>
         </xsl:for-each>
         <xsl:text>&#xA;</xsl:text>
     </xsl:if>
   </xsl:for-each>
 </xsl:template>
</xsl:stylesheet>

при применении к предоставленному документу XML :

<project name="CI">
  <target name="CompileApp">
    <project name="Project1.csproj">
      <target name="build">
        <error>Compilation error one!</error>
      </target>
      <target name="BeforeBuild">
        <project name="Project2.csproj">
          <target name="build">
            <error>Compilation error two!</error>
          </target>
        </project>
      </target>
    </project>
  </target>
</project>

дает желаемый, правильный результат :

 Project Project1.csproj: 1 errors.
 Errors:
 Compilation error one!

 Project Project2.csproj: 1 errors.
 Errors:
 Compilation error two!
1 голос
/ 29 июня 2010

Вот довольно простое решение:

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

  <xsl:template match="/">
    <xsl:apply-templates select="//project[.//error]" />
  </xsl:template>

  <xsl:template match="project">
    <xsl:variable name="errors" select=".//error[ancestor::project[1]/@name = current()/@name]" />
    <xsl:if test="count($errors) != 0">
      <xsl:value-of select="concat('Project &quot;',@name,'&quot;: ',count($errors),' error(s)&#10;Error(s):&#10;')" />
      <xsl:apply-templates select="$errors" />
      <xsl:text>&#10;</xsl:text>
    </xsl:if>
  </xsl:template>

  <xsl:template match="error">
    <xsl:value-of select="concat(.,'&#10;')" />
  </xsl:template>
</xsl:stylesheet>

Эта таблица стилей в основном просто вызывает шаблон для каждого элемента project в любом месте дерева документа. Этот шаблон хранит список всех ошибок в переменной, используя xpath, который выбирает все error элементы, которые являются потомками текущего project и имеют текущий элемент project в качестве первого project предка. Затем, если они есть, он просто выводит соответствующий текст заголовка и применяет шаблон к каждой ошибке.

Я использую &#10; для символа новой строки здесь, но если вы предпочитаете новую строку Windows, вы можете использовать &#13;&#10;.

Незначительное предостережение к этому; в конце вы получите пустую строку в нижней части вашего вывода, так как она добавляет одну в нижней части каждого проекта, чтобы отделить ее от следующего.

0 голосов
/ 29 июня 2010

Мы так привыкли к сложным требованиям, мы озадачены, когда это кажется более простым.

Итак, с:

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

  <xsl:template match="project[../..]">
      <xsl:value-of select="concat('&#xA;',
            'Project &quot;',@name,'&quot;: ',count(target/error),' error(s)&#xA;',
              'Error(s):&#xA;')" />
      <xsl:apply-templates/>
  </xsl:template>

  <xsl:template match="error">
    <xsl:value-of select="concat(.,'&#xA;')" />
  </xsl:template>
</xsl:stylesheet>

Вы получаете:

Project "Project1.csproj": 1 error(s)
Error(s):
Compilation error one!

Project "Project2.csproj": 1 error(s)
Error(s):
Compilation error two!
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...