【问题标题】:XSL: Group parent attributes using matching child attributeXSL:使用匹配的子属性对父属性进行分组
【发布时间】:2015-01-30 08:37:12
【问题描述】:

大家好,我正在尝试使用转换 XML 文档将表格直接输出到 Excel 中。我遇到的问题是我需要按子节点对元素进行分组。我当前的 XSLT 是这样的:

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

<xsl:template match="ScanData">
  <html>
  <body>
  <xsl:for-each select="Report/ReportHost">
    <xsl:if test="ReportItem/@severity &gt; 0">
    <h2><xsl:value-of select="@name"/></h2><br/>
    </xsl:if>
    <xsl:for-each select="ReportItem">
        <xsl:sort select = "@severity" data-type="number" order="descending"/>
        <xsl:sort select = "@pluginID"/>
    <xsl:if test="@severity &gt; 0">
    <xsl:if test="(preceding-sibling::*[1]/@pluginName != @pluginName)">
    <b>Severity: </b><xsl:value-of select="@severity"/><br/>
    <b>Name: </b><xsl:value-of select="@pluginName"/><br/>  
    <b>Synopsis: </b><xsl:value-of select="synopsis"/><br/> 
    <b>Description: </b><xsl:value-of select="description"/><br/>   
    <b>Solution: </b><xsl:value-of select="solution"/><br/> 
    </xsl:if>
    Port:<xsl:value-of select="@protocol"/>/<xsl:value-of select="@port"/><br/>
    </xsl:if>
     </xsl:for-each>
      </xsl:for-each>
  </body>
  </html>
</xsl:template>
</xsl:stylesheet>

示例 XML

<?xml version="1.0" ?>
    <?xml-stylesheet type="text/xsl" href="Internal.xsl"?>
    <ScanData>
        <Report name="Report">
            <ReportHost name="192.168.1.1">      
                <ReportItem port="0" svc_name="general" protocol="tcp" severity="1" pluginID="11936" pluginName="OS Identification" pluginFamily="General">
                    <description>Using a combination of remote probes (TCP/IP, SMB, HTTP, NTP, SNMP, etc...), it is possible to guess the name of the remote operating system in use. It is also sometimes possible to guess the version of the operating system.</description>
                    <fname>os_fingerprint.nasl</fname>
                    <plugin_modification_date>2014/02/19</plugin_modification_date>
                    <plugin_name>OS Identification</plugin_name>
                    <plugin_publication_date>2003/12/09</plugin_publication_date>
                    <plugin_type>combined</plugin_type>
                    <risk_factor>None</risk_factor>
                    <script_version>$Revision: 2.37 $</script_version>
                    <solution>n/a</solution>
                    <synopsis>It is possible to guess the remote operating system.</synopsis>

                </ReportItem>
.....(ReportItem and ReportHost repeat with different findings and hosts)

我遇到的问题是,所有数据都是按主机地址输出的,但我需要按 pluginID 对数据进行分组,因此我需要“带有这些发现的主机”而不是“带有这些发现的主机”。
即:
当前:
ReportHost/@name
查找属性(名称、描述等)
受影响的端口
受影响的端口
受影响的端口
查找属性(名称、描述等)
受影响的端口 em>

ReportHost/@name
查找属性(名称、描述等)
受影响的端口
受影响的港口
.
.
.

必需:
查找属性(名称、描述等)
ReportHost/@name
受影响的端口
受影响的端口
受影响的端口
ReportHost/@name
受影响的端口

查找属性(名称、描述等)
ReportHost/@name
受影响的端口
受影响的港口
.
.

我知道我说过我需要在 excel 中使用它,并且我已经为 excel 制作了一个可行的 XSL 我只是使用 HTML 来方便测试(没有工具,只有 notepad++ 和 Firefox)。对不起,如果我没有很好地解释。我想我需要使用 Muenchian 分组,因为 excel 中不允许使用每个组,但我是 XML 新手,我似乎无法理解它。

提前致谢。

詹姆斯

【问题讨论】:

  • 是否可以修改您的问题以显示稍大的 XML 示例。一个显示属于不同主机/插件的ReportItem 元素!不过,您可以通过删除ReportItem 元素中的一些字段来减小大小。此外,显示该样本的预期实际输出可能是一个好主意。谢谢!

标签: xml excel xslt grouping


【解决方案1】:

这里确实需要 Muenchian Grouping。事实上,您需要使用它两次。首先,您按插件对 ReportItem 元素进行分组,因此您定义了一个这样的键(注意我已经包含了严重性条件,因为它从您现有的 XSLT 中看起来您只需要具有非零严重性的项目)

<xsl:key name="plugin" match="ReportItem[@severity > 0]" use="@pluginID" />

在这个插件“组”中,您需要按ReportHost 对它们进行分组。为此,您定义了第二个键,但由于它是“组内组”,您仍然需要引用插件 ID:

<xsl:key name="plugin_by_report" match="ReportItem[@severity > 0]" use="concat(@pluginID, '|', ../@name)" />

注意这里使用..来获取父元素ReportHost

然后,要获得不同的插件,请使用第一个键

在这个组中,要获得ReportHost 的不同项目,您可以这样做

<xsl:for-each 
     select="key('plugin', @pluginID)
             [generate-id() = generate-id(key('plugin_by_report',concat(@pluginID, '|', ../@name))[1])]">

初学者试试这个 XSL:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output method="xml" indent="yes" />

<xsl:key name="plugin" match="ReportItem[@severity > 0]" use="@pluginID" />
<xsl:key name="plugin_by_report" match="ReportItem[@severity > 0]" use="concat(@pluginID, '|', ../@name)" />

<xsl:template match="ScanData">
    <html>
        <body>
            <xsl:for-each select="Report/ReportHost/ReportItem[generate-id() = generate-id(key('plugin', @pluginID)[1])]">
                <h2>Plugin: <xsl:value-of select="@pluginName"/></h2>
                <xsl:for-each select="key('plugin', @pluginID)[generate-id() = generate-id(key('plugin_by_report',concat(@pluginID, '|', ../@name))[1])]">
                    <h3>Host: <xsl:value-of select="../@name"/></h3>
                    <xsl:apply-templates select="key('plugin_by_report',concat(@pluginID, '|', ../@name))">
                    <xsl:sort select = "@severity" data-type="number" order="descending"/>
                    </xsl:apply-templates>
                </xsl:for-each>
            </xsl:for-each>
        </body>
    </html>
</xsl:template>

<xsl:template match="ReportItem">
    <p>
    Port:<xsl:value-of select="@protocol"/>/<xsl:value-of select="@port"/>
    </p>
</xsl:template>
</xsl:stylesheet>

【讨论】:

  • 你太棒了!非常感谢你,这工作得很好,希望它会被 excel 接受,但不管这是我想要的。看来我真的要靠Muenchian Grouping了。再次感谢!
猜你喜欢
  • 1970-01-01
  • 2016-03-07
  • 1970-01-01
  • 1970-01-01
  • 2015-02-03
  • 2013-04-21
  • 2012-12-17
  • 1970-01-01
  • 2013-07-28
相关资源
最近更新 更多