XSLT无法匹配XML节点:如何提取指定路径的Computer节点
问题描述
我正在编写基础XSLT程序,需要提取路径/Events/Event/System/Computer的节点,实现循环打印计算机名称(示例XML有2个Event节点,需打印两次)。但当前模板无法正确匹配目标节点,输出结构不符合预期,请求解决节点匹配问题。
我的XSLT样式表
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="html" indent="yes"/> <xsl:template match="/"> <html> <body> <h2>Event</h2> <table> <tr> <xsl:apply-templates/> </tr> </table> </body> </html> </xsl:template> <xsl:template match="Event"> <td><xsl:apply-templates select="System"/> </td> </xsl:template> <xsl:template match="System"> <xsl:apply-templates select="Computer"/> </xsl:template> <xsl:template match="Computer"> Computer: <span style="color:#ff0000"> <xsl:value-of select="."/></span> <br /> </xsl:template> </xsl:stylesheet>
XML示例
<?xml version="1.0" encoding="utf-8" standalone="yes"?> <Events> <Event xmlns='http://schemas.microsoft.com/win/2004/08/events/event'> <System> <Provider Name='Application Error'/> <EventID Qualifiers='0'>1000</EventID> <Version>0</Version> <Level>2</Level> <Task>100</Task> <Opcode>0</Opcode> <Keywords>0x80000000000000</Keywords> <TimeCreated SystemTime='2023-01-11T10:22:54.9821986Z'/> <EventRecordID>85280</EventRecordID> <Correlation/> <Execution ProcessID='0' ThreadID='0'/> <Channel>Application</Channel> <Computer>Peru-Desktop</Computer> <Security/> </System> <EventData> <Data>RuntimeBroker.exe</Data> <Data>10.0.19041.746</Data> <Data>5b78739c</Data> <Data>ntdll.dll</Data> <Data>10.0.19041.2130</Data> <Data>b5ced1c6</Data> <Data>c0000374</Data> <Data>00000000000ff6a9</Data> <Data>28c0</Data> <Data>01d9259e77eefd6c</Data> <Data>C:\Windows\System32\RuntimeBroker.exe</Data> <Data>C:\Windows\SYSTEM32\ntdll.dll</Data> <Data>66a01ef8-5dc9-4305-8670-d39ef7144aaf</Data> <Data>Microsoft.Windows.Search_1.14.7.19041_neutral_neutral_cw5n1h2txyewy</Data> <Data>runtimebroker07f4358a809ac99a64a67c1</Data> </EventData> </Event> <Event xmlns='http://schemas.microsoft.com/win/2004/08/events/event'> <System> <Provider Name='Application Error'/> <EventID Qualifiers='0'>1000</EventID> <Version>0</Version> <Level>2</Level> <Task>100</Task> <Opcode>0</Opcode> <Keywords>0x80000000000000</Keywords> <TimeCreated SystemTime='2023-01-11T05:17:35.3925442Z'/> <EventRecordID>85258</EventRecordID> <Correlation/> <Execution ProcessID='0' ThreadID='0'/> <Channel>Application</Channel> <Computer>Peru-Desktop</Computer> <Security/> </System> <EventData> <Data>ftnlsv.exe</Data> <Data>3.3.10.0</Data> <Data>5fa14984</Data> <Data>ntdll.dll</Data> <Data>10.0.19041.2130</Data> <Data>b5ced1c6</Data> <Data>c0000409</Data> <Data>000000000008c67f</Data> <Data>15bc</Data> <Data>01d925799d1bd691</Data> <Data>C:\Program Files\Common Files\VMware\DeviceRedirectionCommon\ftnlsv.exe</Data> <Data>C:\Windows\SYSTEM32\ntdll.dll</Data> <Data>96b01680-a7d7-4e54-b2a8-b350ed24498d</Data> <Data></Data> <Data></Data> </EventData> </Event> </Events>
当前不符合预期的输出
<!DOCTYPE html> <html> <body> <h2>Event</h2> <table> <tr><td>Computer: <span style="color:#ff0000">Peru-Desktop</span><br /></td></tr> <tr><td>Computer: <span style="color:#ff0000">Peru-Desktop</span><br /></td></tr> </table></body></html>
问题原因
XML中的Event、System、Computer节点都属于命名空间http://schemas.microsoft.com/win/2004/08/events/event,但你的XSLT没有声明该命名空间,也没有使用命名空间前缀匹配节点,导致模板无法正确命中目标节点,当前输出是XSLT默认模板遍历节点后的结果,结构不符合预期。
解决方案
在XSLT中声明该命名空间的前缀,并在模板匹配和节点选择时使用前缀:
<?xml version="1.0" encoding="UTF-8"?> <!-- 声明命名空间前缀 ev,绑定到XML中的事件命名空间 --> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ev="http://schemas.microsoft.com/win/2004/08/events/event"> <xsl:output method="html" indent="yes"/> <xsl:template match="/"> <html> <body> <h2>Event</h2> <table> <tr> <!-- 明确选择Events下的ev:Event节点 --> <xsl:apply-templates select="Events/ev:Event"/> </tr> </table> </body> </html> </xsl:template> <!-- 匹配带命名空间的Event节点 --> <xsl:template match="ev:Event"> <td><xsl:apply-templates select="ev:System"/> </td> </xsl:template> <!-- 匹配带命名空间的System节点 --> <xsl:template match="ev:System"> <xsl:apply-templates select="ev:Computer"/> </xsl:template> <!-- 匹配带命名空间的Computer节点 --> <xsl:template match="ev:Computer"> Computer: <span style="color:#ff0000"> <xsl:value-of select="."/></span> <br /> </xsl:template> </xsl:stylesheet>
修正后输出
<!DOCTYPE html> <html> <body> <h2>Event</h2> <table> <tr> <td>Computer: <span style="color:#ff0000">Peru-Desktop</span><br /></td> <td>Computer: <span style="color:#ff0000">Peru-Desktop</span><br /></td> </tr> </table> </body> </html>
如果希望每个Event单独占一行(即每个Event对应一个<tr>),可以调整根模板中的结构:
<xsl:template match="/"> <html> <body> <h2>Event</h2> <table> <!-- 遍历每个ev:Event,为每个Event生成一行 --> <xsl:for-each select="Events/ev:Event"> <tr> <xsl:apply-templates select="."/> </tr> </xsl:for-each> </table> </body> </html> </xsl:template>
这样输出的每个计算机名称会单独占一行表格,符合常见的表格布局习惯。
内容的提问来源于stack exchange,提问作者Perumal Rm
相关产品推荐
相关产品推荐

