2016-01-18 5 views
0

Я следую инструкциям на http://www.ibm.com/developerworks/library/x-tipcombxslt/, чтобы объединить мои XML-файлы. Тем не менее, я хотел бы сделать больше задач сразу и не могу найти способ сделать это. В принципе, я хочу отфильтровать ввод слияния (работает уже) и сортировать вывод (нужна помощь).Фильтровать, объединять и сортировать списки узлов XML

source.xml определяет файлы, содержащие узлы (в моем случае стандартные нарушения кодирования), которые необходимо объединить. Однако некоторые из них содержат нарушения большего количества правил, чем я хочу сохранить на выходе, поэтому я указываю <rule>, чтобы сохранить в пределах <ruleset>. Когда правила не указаны, все правила должны быть сохранены.

<rulesets> 
    <ruleset file="ruleset_M1.xml"/> 
    <ruleset file="ruleset_all2.xml"> 
    <rule>X</rule> 
    <rule>Y</rule> 
    </ruleset> 
</rulesets> 

Так вот я хочу, чтобы все правила из ruleset_M1.xml и правил X и Y от ruleset_all2.xml.

ruleset_all2.xml выглядит следующим образом:

<violations> 
    <violation file="Bra.h" line="1" rule="Z" 
      msg="Function SPARC_Convert is not documented."/> 
    <violation file="CpuArch.h" line="120" rule="X" 
      msg="Parameters of member GetBe32 are not documented."/> 
    <violation file="CpuArch.h" line="87" rule="X" 
      msg="Parameters of member GetUi32 are not documented."/> 
    <violation file="heapmgr.h" line="56" rule="Y" 
      msg="The following parameter of HeapManager() is not documented: fill"/> 
</violations> 

и ruleset_M1.xml содержит гораздо больше нарушений гораздо больше правил, которые все должны быть сохранены.

Мне удалось выполнить фильтрацию и слияние с использованием следующего XSLT.

<xsl:stylesheet version="2.0"> 
    <xsl:template match="/rulesets"> 
    <violations> 
     <xsl:apply-templates> 
     <xsl:sort select="@file"/><!-- help needed --> 
     </xsl:apply-templates> 
    </violations> 
    </xsl:template> 

    <xsl:template match="ruleset"> 
    <xsl:choose> 
     <xsl:when test="rule != ''"> 
     <xsl:variable name="current-rules" select="rule"/> 
     <xsl:copy-of select="document(@file)/violations/violation[@rule = $current-rules]"/> 
     </xsl:when> 
     <xsl:otherwise> 
     <xsl:copy-of select="document(@file)/violations/violation"/> 
     </xsl:otherwise> 
    </xsl:choose> 
    </xsl:template> 
</xsl:stylesheet> 

Теперь я хочу, чтобы отсортировать вывод по имени файла (violation/@file), но мой <xsl:sort> не работает. XPath @file соответствует атрибуту <ruleset>, а не <violation>. Я попытался заменить его document(@file)/violations/violation/@file и несколькими другими вариантами без успеха. Можно ли каким-либо образом выбрать атрибут в выходных узлах второго шаблона вместо текущего источника? Или я должен полностью изменить свой XSL?

ответ

1

Если слияние работает, я думаю, проще всего слить первый, а затем сортировать путем изменения

<xsl:template match="/rulesets"> 
    <violations> 
     <xsl:apply-templates> 
     <xsl:sort select="@file"/><!-- help needed --> 
     </xsl:apply-templates> 
    </violations> 
    </xsl:template> 

в

<xsl:template match="/rulesets"> 
    <violations> 
     <xsl:variable name="merged"> 
     <xsl:apply-templates select="ruleset"/> 
     </xsl:variable> 
     <xsl:perform-sort select="$merged/violation"> 
     <xsl:sort select="@file"/> 
     </xsl:perform-sort> 
    </violations> 
    </xsl:template> 

и в любое время я вижу матч с XSL: выбрать, как и в

<xsl:template match="ruleset"> 
    <xsl:choose> 
     <xsl:when test="rule != ''"> 
     <xsl:variable name="current-rules" select="rule"/> 
     <xsl:copy-of select="document(@file)/violations/violation[@rule = $current-rules]"/> 
     </xsl:when> 
     <xsl:otherwise> 
     <xsl:copy-of select="document(@file)/violations/violation"/> 
     </xsl:otherwise> 
    </xsl:choose> 
    </xsl:template> 

Я думаю, что она должна быть перестроена в

<xsl:template match="ruleset[rule]"> 
    <xsl:copy-of select="document(@file)/violations/violation[@rule = current()/rule]"/> 
</xsl:template> 

<xsl:template match="ruleset[not(rule)]"> 
    <xsl:copy-of select="document(@file)/violations/violation"/> 
</xsl:template> 

В качестве альтернативы, я думаю, вы могли бы использовать

<xsl:template match="/rulesets"> 
    <violations> 
     <xsl:perform-sort select="for $rs in ruleset[rule] return document($rs/@file)/violations/violation[@rule = $rs/rule], for $rs2 in ruleset[not(rule)] return document($rs2/@file)/violations/violation"> 
     <xsl:sort select="@file"/> 
     </xsl:apply-templates> 
    </violations> 
    </xsl:template> 

вместо

<xsl:template match="/rulesets"> 
    <violations> 
     <xsl:apply-templates> 
     <xsl:sort select="@file"/><!-- help needed --> 
     </xsl:apply-templates> 
    </violations> 

Смежные вопросы