XSL:使用匹配的子属性对父属性进行分组
XSL: Group parent attributes using matching child attribute
大家好,我正在尝试使用转换 XML 文档将 table 直接输出到 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 > 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 > 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 对数据进行分组,所以我需要 "Findings with these hosts".[=52 而不是 "Host with these findings" =]
即:
当前:
ReportHost/@name
查找属性(名称、描述等)
受影响的端口
受影响的端口
受影响的端口
查找属性(名称、描述等)
受影响的端口
ReportHost/@name
查找属性(名称、描述等)
受影响的端口
受影响的端口
.
.
.
必填:
查找属性(名称、描述等)
ReportHost/@name
受影响的端口
受影响的端口
受影响的端口
ReportHost/@name
受影响的端口
查找属性(名称、描述等)
ReportHost/@name
受影响的端口
受影响的端口
.
.
我知道我在 excel 中说过我需要它,并且我已经为 excel 制作了一个可用的 XSL 我只是为了方便测试而使用 HTML(没有工具只有 notepad++ 和 Firefox)。对不起,如果我没有解释得很好。我想我需要使用 Muenchian 分组,因为 excel 中不允许使用 for-each-group,但我是一个 XML 菜鸟,我似乎无法理解它。
提前致谢。
詹姆斯
您确实需要 Muenchian 分组。事实上,你需要使用它两次。首先,您按插件对 ReportItem
元素进行分组,因此您可以像这样定义一个键(请注意,我已经包含了关于严重性的条件,因为它从您现有的 XSLT 中看起来您只需要具有非零严重性的项目)
<xsl:key name="plugin" match="ReportItem[@severity > 0]" use="@pluginID" />
在这个 "group" 插件中,您需要按 ReportHost
对它们进行分组。为此,您定义了第二个密钥,但因为它是 "group-within-a-group" 您仍然需要引用插件 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>
大家好,我正在尝试使用转换 XML 文档将 table 直接输出到 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 > 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 > 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 对数据进行分组,所以我需要 "Findings with these hosts".[=52 而不是 "Host with these findings" =]
即:
当前:
ReportHost/@name
查找属性(名称、描述等)
受影响的端口
受影响的端口
受影响的端口
查找属性(名称、描述等)
受影响的端口
ReportHost/@name
查找属性(名称、描述等)
受影响的端口
受影响的端口
.
.
.
必填:
查找属性(名称、描述等)
ReportHost/@name
受影响的端口
受影响的端口
受影响的端口
ReportHost/@name
受影响的端口
查找属性(名称、描述等)
ReportHost/@name
受影响的端口
受影响的端口
.
.
我知道我在 excel 中说过我需要它,并且我已经为 excel 制作了一个可用的 XSL 我只是为了方便测试而使用 HTML(没有工具只有 notepad++ 和 Firefox)。对不起,如果我没有解释得很好。我想我需要使用 Muenchian 分组,因为 excel 中不允许使用 for-each-group,但我是一个 XML 菜鸟,我似乎无法理解它。
提前致谢。
詹姆斯
您确实需要 Muenchian 分组。事实上,你需要使用它两次。首先,您按插件对 ReportItem
元素进行分组,因此您可以像这样定义一个键(请注意,我已经包含了关于严重性的条件,因为它从您现有的 XSLT 中看起来您只需要具有非零严重性的项目)
<xsl:key name="plugin" match="ReportItem[@severity > 0]" use="@pluginID" />
在这个 "group" 插件中,您需要按 ReportHost
对它们进行分组。为此,您定义了第二个密钥,但因为它是 "group-within-a-group" 您仍然需要引用插件 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>