【问题标题】:XSLT transformation XML-to-CSV accessing nested elements with same nameXSLT 转换 XML 到 CSV 访问具有相同名称的嵌套元素
【发布时间】:2021-11-24 15:01:43
【问题描述】:

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

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

File@path="filename1.txt" |规则@id="3.1.6" |消息@severity="3" | Message@text="3480......."

File@path="filename1.txt" |规则@id="3.5.19" |消息@severity="3" | Message@text="1281......."

File@path="filename2.txt" |规则@id="3.1.6" |消息@severity="3" | Message@text="3480......."

File@path="filename2.txt" |规则@id="3.5.3" |消息@severity="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>

【问题讨论】:

    标签: xslt xslt-2.0 transformation xslt-3.0 xmltocsv


    【解决方案1】:

    我通常建议为映射到一行的元素编写一个模板,然后使用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>
    

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

    <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>
    

    【讨论】:

    • 我刚刚在一个大输入文件中发现一个规则可能包含多个消息。您能否告诉我应该对现有 XSLT 进行哪些更改?
    • @Flaviu,好吧,尝试自己调整建议的代码,或者至少明确描述如果规则有多个消息,输出会发生什么,你想要一行每条消息或每条规则一行,然后有几列用于消息?
    • 每行显示两条消息 (filename.txt;3.5.2;3;0654。[U] 在函数返回类型中使用 'const' 或 'volatile' 是未定义的。;3;0914。 [U] 源文件不以换行符结尾。)在这种情况下,我想要两行具有相同的文件名。这意味着每条消息具有相同文件名的一行。
    • 正如我所说,匹配你想要映射到模板中的一行的元素,所以不要尝试 select="/AnalysisData/dataroot[@type = 'per-file']/File/tree/RuleGroup[@name = 'MISRA_C']//Rule[Message]" 尝试 select="/AnalysisData/dataroot[@type = 'per-file']/File/tree/RuleGroup[@name = 'MISRA_C']//Message" 加上 match="Message" 然后而不是 match="Rule" 并调整选择“列”例如select="ancestor::File/@path, ../@id, @severity, @text"select="mf:line((ancestor::File/@path, ../@id, @severity, @text))".
    • 完美运行!再次感谢
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-30
    • 1970-01-01
    • 1970-01-01
    • 2019-02-15
    • 1970-01-01
    相关资源
    最近更新 更多