XSLT XPATH 出错(表达式必须计算为节点集)
Posted
技术标签:
【中文标题】XSLT XPATH 出错(表达式必须计算为节点集)【英文标题】:Error with XSLT XPATH (Expression must evaluate to a node-set) 【发布时间】:2020-07-13 16:36:20 【问题描述】:我有如下的 XML
<Employees>
<Employee>
<ID>100</ID>
<FirstName>Bala</FirstName>
<LastName>Murugan</LastName>
<Dept>Production Support</Dept>
</Employee>
<Employee0>
<ID>101</ID>
<FirstName>Peter</FirstName>
<LastName>Laurence</LastName>
<Dept>Development</Dept>
</Employee0>
<Employee1>
<ID>102</ID>
<FirstName>Rick</FirstName>
<LastName>Anderson</LastName>
<Dept>Sales</Dept>
</Employee1>
</Employees>
我想向其中一位员工展示使用以下 XSLT
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:param name="SLCT"/>
<xsl:template match="/">
<xsl:for-each select="$SLCT">
<div style="border:1px black solid;width:300px;margin:1px">
<div>
<b>Employee ID:</b>
<xsl:value-of select="ID"/>
</div>
<div>
<b>Name:</b>
<xsl:value-of select="FirstName"/>
<xsl:text> </xsl:text>
<xsl:value-of select="LastName"/>
</div>
<div>
<b>Department:</b>
<xsl:value-of select="Dept"/>
</div>
</div>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
(for-each select="$SLCT") 的问题,它不接受来自 C# 的参数。
我的 C# 代码
protected void Page_Load(object sender, EventArgs e)
string strXSLTFile = Server.MapPath("EmployeeXSLT.xslt");
string strXMLFile = Server.MapPath("Employess.xml");
XmlReader reader = XmlReader.Create(strXMLFile);
XslCompiledTransform objXSLTransform = new XslCompiledTransform();
objXSLTransform.Load(strXSLTFile);
// Create the XsltArgumentList.
XsltArgumentList argList = new XsltArgumentList();
// Set new value to the parameter
argList.AddParam("SLCT", "", "(//Employee)[1]");
XmlWriter writer = XmlWriter.Create(Server.MapPath("OutPut.xml"));
objXSLTransform.Transform(new XPathDocument(strXMLFile), argList, writer);
//Expression must evaluate to a node-set
writer.Close();
reader.Close();
Xml2.DocumentSource = Server.MapPath("~/test/Employess.xml");
Xml2.TransformSource = Server.MapPath("~/test/OutPut.xml");
Xml2.DataBind();
我得到了代码中注释的这个异常(//表达式必须评估为节点集)。但是,当我直接在 XSLT 文件中使用“(//Employee)[1]”或“//Employee”而不是使用参数 (SLCT) 时,我得到了所需的结果。那么,问题出在哪里呢?
【问题讨论】:
到底谁认为为每个员工使用不同的元素名称是一个聪明的主意?很难想到一种设计选择会使处理难度增加五倍,并且绝对没有任何补偿性好处, 【参考方案1】:xsl:for-each
指令的select
属性中使用的 XPath 表达式无法在运行时动态计算。
由于您的 XML 对每个员工记录使用不同的元素名称(Employee
、Employee0
、Employee1
等),您可以将所需元素的名称作为参数传递,然后使用谓词。
例如,下面的样式表:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" omit-xml-declaration="yes" version="1.0" encoding="utf-8" indent="yes"/>
<xsl:param name="SLCT"/>
<xsl:template match="/Employees">
<xsl:variable name="emp" select="*[name()=$SLCT]" />
<div>
<b>Employee ID:</b>
<xsl:value-of select="$emp/ID"/>
</div>
</xsl:template>
</xsl:stylesheet>
当使用"Employee0"
的值调用SLCT
参数时,将返回:
结果
<div><b>Employee ID:</b>101</div>
注意:
因为只有一个元素会满足谓词,所以我使用了一个变量而不是xsl:for-each
。但它也可以使用:
<xsl:template match="/Employees">
<xsl:for-each select="*[name()=$SLCT]">
<div>
<b>Employee ID:</b>
<xsl:value-of select="ID"/>
</div>
</xsl:for-each>
</xsl:template>
【讨论】:
【参考方案2】:您的 XML 需要一些改进。无需为每个员工使用不同的 XML 元素名称。您可以根据唯一 ID 元素值检索特定员工:100、101 等。我调整了 XSLT 以接受该类型的参数。请在下面查看。
XML
<?xml version="1.0"?>
<Employees>
<Employee>
<ID>100</ID>
<FirstName>Bala</FirstName>
<LastName>Murugan</LastName>
<Dept>Production Support</Dept>
</Employee>
<Employee>
<ID>101</ID>
<FirstName>Peter</FirstName>
<LastName>Laurence</LastName>
<Dept>Development</Dept>
</Employee>
<Employee>
<ID>102</ID>
<FirstName>Rick</FirstName>
<LastName>Anderson</LastName>
<Dept>Sales</Dept>
</Employee>
</Employees>
XSLT
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes" omit-xml-declaration="yes"/>
<xsl:param name="SLCT">100</xsl:param>
<xsl:template match="/">
<xsl:apply-templates select="Employees/Employee[ID=$SLCT]"/>
</xsl:template>
<xsl:template match="Employee">
<div style="border:1px black solid;width:300px;margin:1px">
<div>
<b>Employee ID:</b>
<xsl:value-of select="ID"/>
</div>
<div>
<b>Name:</b>
<xsl:value-of select="concat(FirstName,' ',LastName)"/>
</div>
<div>
<b>Department:</b>
<xsl:value-of select="Dept"/>
</div>
</div>
</xsl:template>
</xsl:stylesheet>
c#
// Set new value to the parameter
argList.AddParam("SLCT", "", "101");
输出
<div style="border:1px black solid;width:300px;margin:1px">
<div>
<b>Employee ID:</b>101
</div>
<div>
<b>Name:</b>Peter Laurence
</div>
<div>
<b>Department:</b>Development
</div>
</div>
【讨论】:
你不能自己编问题。 让我们等待 OP 的回复。以上是关于XSLT XPATH 出错(表达式必须计算为节点集)的主要内容,如果未能解决你的问题,请参考以下文章