我有一个带有MySQL Query Browser的XML产品。 我正在尝试应用XSLT将结果输出到Word表中。每张记录一张表。
以下是我的XML样本
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE ROOT SYSTEM "Nessus.dtd">
<ROOT>
<row>
<field name="Niveau">Critique</field>
<field name="Name">Apache 2.2 < 2.2.15 Multiple Vulnerabilities</field>
</row>
<row>
<field name="Niveau">Critique</field>
<field name="VulnName">Microsoft Windows 2000 Unsupported Installation Detection</field>
</row>
<row>
<field name="Niveau">Haute</field>
<field name="VulnName">CGI Generic SQL Injection</field>
</row>
</ROOT>
对于XLST,我已经发现我需要做一个for-each select
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/">
<xsl:for-each select="ROOT/row">
Niveau : <xsl:value-of select="????"/>
Name : <xsl:value-of select="????"/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
当我执行此循环时,我看到与我的文件中有<row></row>
相同数量的空表。
但我还没有找到合适的“值 - 选择=”的方法。我没有运气就尝试了以下内容。
<xsl:value-of select="@name"/>
<xsl:value-of select="name"/>
<xsl:value-of select="@row/name"/>
<xsl:value-of select="row/@name"/>
<xsl:value-of select="@ROOT/row/name"/>
还有一些我不记得了。知道我需要制作请求以获取生成的文件中的值吗?
我刚试过:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/">
<xsl:for-each select="ROOT/row">
Niveau : <xsl:value-of select="field/@Niveau"/>
Name : <xsl:value-of select="field/@name"/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
输出这个:
NIVEAU :
NAME : name
NIVEAU :
NAME : Niveau
NIVEAU :
NAME : Niveau
我想要这个输出:
NIVEAU : Critique
NAME : Apache 2.2 < 2.2.15 Multiple Vulnerabilities
NIVEAU : Critique
NAME : Microsoft Windows 2000 Unsupported Installation Detection
NIVEAU : Haute
NAME : CGI Generic SQL Injection
任何帮助都将不胜感激。
谢谢。
现在有了这个XSLT
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="2.0">
<xsl:output method="text"/>
<xsl:strip-space elements="*"/>
<xsl:template match="row">
<xsl:text>NIVEAU : </xsl:text>
<xsl:value-of select="field[@name = 'Niveau']"/>
<xsl:text>
</xsl:text>
<xsl:text>NAME : </xsl:text>
<xsl:value-of select="field[@name = 'Name']"/>
<xsl:text>

</xsl:text>
</xsl:template>
</xsl:stylesheet>
我得到了这个输出:
<?xml version="1.0"?>
NIVEAU :
NAME : Apache 2.2 < 2.2.15 Multiple Vulnerabilities
NIVEAU : Critique
NAME : Microsoft Windows 2000 Unsupported Installation Detection
NIVEAU : Haute
NAME : CGI Generic SQL Injection
如您所见,第一个字段为空。我可以诚实地接受它,并手动填写它,但如果你知道为什么会这样,我会非常高兴:))
使用<xsl:value-of select="field[@name = 'foo']"/>
给了我想要的价值。我保留了for-each,因为它在MS Word模板中更容易使用(对我而言)。
答案 0 :(得分:3)
for-each
通常是XSLT中的代码味道。你很可能想要一个模板,而不是for-each循环:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="/">
<root>
<xsl:apply-templates/>
</root>
</xsl:template>
<xsl:template match="field">
<xsl:value-of select="@name"/> : <xsl:value-of select="."/>
</xsl:template>
</xsl:stylesheet>
此模板将产生以下输出:
<root>
Niveau : Critique
name : Apache 2.2 < 2.2.15 Multiple Vulnerabilities
Niveau : Critique
name : Microsoft Windows 2000 Unsupported Installation Detection
Niveau : Haute
name : CGI Generic SQL Injection
</root>
XSLT是为这种使用模式而设计的 - 许多xsl:template
匹配源的一小部分并递归应用其他模板。此模式中最重要和最常见的模板是身份模板,它复制输出。你应该阅读This is a good tutorial on XSLT coding patterns。
下面是一个完整的解决方案,它将生成 text 输出(因为这是你想要的,而不是XML输出)。我不确定xsl是否是最好的语言,但它可以工作....
请注意,我们使用for-each
的唯一地方是进行排序以确定最长名称的长度。我们使用模板和模式匹配select
来隐藏所有其他循环。
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="text"/>
<xsl:strip-space elements="*"/>
<xsl:variable name="newline"><xsl:text>
</xsl:text></xsl:variable>
<!-- determine the maximum length of the "name" field so we can pad with spaces for all shorter items -->
<xsl:variable name="max_name_len">
<xsl:for-each select="ROOT/row/field/@name">
<xsl:sort select="string-length(.)" data-type="number" order="descending"/>
<xsl:if test="position() = 1">
<xsl:value-of select="string-length(.)"/>
</xsl:if>
</xsl:for-each>
</xsl:variable>
<!-- for each row, apply templates then add a blank line -->
<xsl:template match="row">
<xsl:apply-templates/>
<xsl:value-of select="$newline"/>
</xsl:template>
<!-- for each field, apply template to name and add value, followed by a newline -->
<xsl:template match="field">
<xsl:apply-templates select="@name"/> : <xsl:value-of select="concat(., $newline)"/>
</xsl:template>
<!-- for each name, uppercase and pad with spaces to the right -->
<xsl:template match="field/@name">
<xsl:call-template name="padright">
<xsl:with-param name="text">
<xsl:call-template name="toupper">
<xsl:with-param name="text" select="."/>
</xsl:call-template>
</xsl:with-param>
<xsl:with-param name="len" select="$max_name_len"/>
</xsl:call-template>
</xsl:template>
<!-- Utility function: uppercase a string -->
<xsl:template name="toupper">
<xsl:param name="text"/>
<xsl:value-of select="translate($text, 'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ')"/>
</xsl:template>
<!-- Utility function: pad a string to desired len with spaces on the right -->
<!-- uses a recursive solution -->
<xsl:template name="padright">
<xsl:param name="text"/>
<xsl:param name="len"/>
<xsl:choose>
<xsl:when test="string-length($text) < $len">
<xsl:call-template name="padright">
<xsl:with-param name="text" select="concat($text, ' ')"/>
<xsl:with-param name="len" select="$len"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$text"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
此样式表产生以下输出:
NIVEAU : Critique
NAME : Apache 2.2 < 2.2.15 Multiple Vulnerabilities
NIVEAU : Critique
NAME : Microsoft Windows 2000 Unsupported Installation Detection
NIVEAU : Haute
NAME : CGI Generic SQL Injection
答案 1 :(得分:1)
执行<xsl:for-each select="ROOT/row">
时,循环内的当前上下文是row
元素。因此,为了访问字段名称,您需要编写例如<xsl:value-of select="field/@name"/>
。
由于您的XML包含多个字段,因此您仍需要稍微扩展XSLT文件以迭代字段,或者(正如Francis Avila建议的那样)编写模板。但是这两种方法都没问题。这两种方法的技术术语分别是“拉”和“推”。
当然,由于您最终想要生成单词表,因此您必须生成w:tr
和w:tc
元素等。
答案 2 :(得分:0)
此样式表将为您提供所需的输出
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="2.0">
<xsl:output method="text"/>
<xsl:strip-space elements="*"/>
<xsl:template match="row">
<xsl:text>NIVEAU : </xsl:text>
<xsl:value-of select="field[@name eq 'Niveau']"/>
<xsl:text>
</xsl:text>
<xsl:text>NAME : </xsl:text>
<xsl:value-of select="field[@name eq 'VulnName']"/>
<xsl:text>

</xsl:text>
</xsl:template>
</xsl:stylesheet>
这非常特定于您输入的xml和输出文本,例如除了{Niveau&#39;以外的<field>
<row>
个孩子。或者&#39; VulnName&#39;将从您的报告中删除。更通用的解决方案可能如下所示:
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="2.0">
<xsl:output method="text"/>
<xsl:template match="field">
<xsl:value-of select="concat(upper-case(@name),': ',.)"/>
</xsl:template>
</xsl:stylesheet>
此解决方案并不完全匹配所需输出中的空白格式,但它确实捕获了所有可能的字段。