XSLT 转换 XML-to-CSV 访问具有相同名称的嵌套元素

XSLT transformation XML-to-CSV accessing nested elements with same name

我正在尝试将下面的 XML 示例转换为 CSV,但我很难匹配具有相同名称(规则)的嵌套元素。

可以生成此结构的 XSLT 转换是什么?

文件@路径="filename1.txt" |规则@id="3.1.6" |消息@严重性=“3” | Message@text="3480. ....."

文件@路径="filename1.txt" |规则@id="3.5.19" |消息@严重性=“3” | Message@text="1281. ....."

文件@路径="filename2.txt" |规则@id="3.1.6" |消息@严重性=“3” | Message@text="3480. ....."

文件@路径="filename2.txt" |规则@id="3.5.3" |消息@严重性=“3” | Message@text="3219. ....."

路径看起来像:

AnalysisData\dataroot type="per-file"\File\tree type="rules"\RuleGroup name="MISRA_C"\...\Rule id="[1-9]+\.[1-9]+\.[1-9]+"\Message

输入XML是:

<AnalysisData>
  <dataroot type="project">
  </dataroot>
  <dataroot type="per-file">
    <File path="filename1.txt">
      <Json>1.json</Json>
      <tree type="rules">
        <RuleGroup name="MISRA_C" total="2" active="2" >
          <Rule id="3" total="2" active="2" text="Mandatory" >
            <Rule id="3.1" total="1" active="1" text="Common" >
              <Rule id="3.1.6" total="1" active="1" text="Declarations and definitions" >
                <Message guid="qac-9.6.0-3480" total="1" active="1" severity="3" text="3480.  Object/function '%s', with internal linkage, has been defined in a header file." />
              </Rule>
            </Rule>
            <Rule id="3.5" total="1" active="1" text="MISRA Required Rules" >
              <Rule id="3.5.19" total="1" active="1" text="M3CM Rule-7.2 A &quot;u&quot; or &quot;U&quot; suffix shall be applied to all integer constants that are represented in an unsigned type" >
                <Message guid="qac-9.6.0-1281" total="1" active="1" severity="3" text="1281.  Integer literal constant is of an unsigned type but does not include a &quot;U&quot; suffix." />
              </Rule>
            </Rule>
          </Rule>
        </RuleGroup>
      </tree>
    </File>
    <File path="filename2.txt">
      <Json>2.json</Json>
      <tree type="rules">
        <RuleGroup name="CrossModuleAnalysis" total="11" active="11" >
          <Rule id="1" total="11" active="11" text="Maintainability" >
            <Rule id="1.1" total="11" active="11" text="CMA Declaration Standards" >
              <Message guid="rcma-2.0.0-1534" total="11" active="11" severity="2" text="1534.  The macro '%1s' is declared but not used within this project." />
            </Rule>
          </Rule>
        </RuleGroup>
        <RuleGroup name="MISRA_C" total="36" active="16" >
          <Rule id="3" total="20" active="0" text="Mandatory" >
            <Rule id="3.1" total="12" active="0" text="Common" >
              <Rule id="3.1.6" total="12" active="0" text="Declarations and definitions" >
                <Message guid="qac-9.6.0-3480" total="12" active="0" severity="3" text="3480.  Object/function '%s', with internal linkage, has been defined in a header file." />
              </Rule>
            </Rule>
            <Rule id="3.5" total="8" active="0" text="MISRA Required Rules" >
              <Rule id="3.5.3" total="8" active="0" text="M3CM Rule-2.1 A project shall not contain unreachable code" >
                <Message guid="qac-9.6.0-3219" total="8" active="0" severity="3" text="3219.  Static function '%s()' is not used within this translation unit." />
              </Rule>
            </Rule>
          </Rule>
          <Rule id="2" total="16" active="16" text="Minor" >
            <Rule id="2.1" total="16" active="16" text="Common" >
              <Rule id="2.1.15" total="16" active="16" text="Declarations and Definitions" >
                <Message guid="qac-9.6.0-3227" total="16" active="16" severity="2" text="3227.  The parameter '%s' is never modified and so it could be declared with the 'const' qualifier." />
              </Rule>
            </Rule>
          </Rule>
        </RuleGroup>
      </tree>
    </File>
  </dataroot>
</AnalysisData>

我通常建议为映射到一行的元素编写一个模板,然后使用 xsl:value-of separator 输出带有您选择的分隔符的行:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  version="3.0"
  xmlns:xs="http://www.w3.org/2001/XMLSchema"
  exclude-result-prefixes="#all"
  expand-text="yes">

  <xsl:output method="text"/>

  <xsl:template match="/" name="xsl:initial-template">
    <xsl:apply-templates 
      select="/AnalysisData/dataroot[@type = 'per-file']/File/tree/RuleGroup[@name = 'MISRA_C']//Rule[Message]"/>
  </xsl:template>
  
  <xsl:template match="Rule">
    <xsl:value-of select="ancestor::File/@path, @id, Message!(@severity, @text)" separator=" | "/>
    <xsl:text>&#10;</xsl:text>
  </xsl:template>

</xsl:stylesheet>

如果您想输出属性值加上 element/attribute 名称,那么一个函数可能会有所帮助:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  version="3.0"
  xmlns:xs="http://www.w3.org/2001/XMLSchema"
  xmlns:mf="http://example.com/mf"
  exclude-result-prefixes="#all"
  expand-text="yes">

  <xsl:output method="text"/>
  
  <xsl:function name="mf:line" as="xs:string*">
    <xsl:param name="atts" as="attribute()*"/>
    <xsl:sequence
      select="$atts ! (local-name(..) || '@' || local-name() || '=&quot;' || . || '&quot;')"/>
  </xsl:function>

  <xsl:template match="/" name="xsl:initial-template">
    <xsl:apply-templates 
      select="/AnalysisData/dataroot[@type = 'per-file']/File/tree/RuleGroup[@name = 'MISRA_C']//Rule[Message]"/>
  </xsl:template>
  
  <xsl:template match="Rule">
    <xsl:value-of select="mf:line((ancestor::File/@path, @id, Message!(@severity, @text)))" separator=" | "/>
    <xsl:text>&#10;</xsl:text>
  </xsl:template>

</xsl:stylesheet>