为什么在SOAP标头中包含某些内容会阻止它与XSLT模板匹配
本文关键字:XSLT SOAP 包含某 为什么 | 更新日期: 2023-09-27 18:00:07
我有一个SOAP(1.1)信封,内容如下:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:l3="http://tempuri.org/l3">
<soapenv:Header>
<l3:requestType>Valid</l3:requestType>
</soapenv:Header>
<soapenv:Body>
<l3:xyzRequest xsi:schemaLocation="http://tempuri.org/l3 lds.xsd " requestId="7291655" functionalId="1645885" appChannel="XYZ" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<workpackageId>126381</workpackageId>
...
</l3:xyzRequest>
</soapenv:Body>
</soapenv:Envelope>
还有一个类似于以下内容的XSLT模板:
<xsl:template match="soapenv:Envelope/soapenv:Body/l3:xyzRequest">
...
</xsl:template>
我在Visual Studio 2013(.NET Framework 4.5.1)中使用C#
XslCompiledTransform xslt = new XslCompiledTransform(false);
StringBuilder sb = new StringBuilder();
xslt.Load(@"<XSLTPath>");
using (XmlWriter xw = XmlWriter.Create(sb, xslt.OutputSettings))
{
xslt.Transform(XML.CreateReader(), xw);
}
当我运行转换时,模板不匹配,但如果我从SOAP标头中删除<l3:requestType>
元素(不做任何其他更改),它就可以正常工作。有人知道为什么吗?
编辑:
根据提供更多代码的请求,这里有一个将重现问题的最小样本:
using System;
using System.Text;
using System.Xml;
using System.Xml.Linq;
using System.Xml.Xsl;
namespace Project1
{
class Program
{
static void Main()
{
XDocument XSL = XDocument.Parse("<xsl:stylesheet xmlns:xsl='"http://www.w3.org/1999/XSL/Transform'" xmlns:soapenv='"http://schemas.xmlsoap.org/soap/envelope/'" xmlns:l3='"http://tempuri.org/l3'" version='"1.0'">" +
"<xsl:output method='"xml'" />" +
"<xsl:template match='"soapenv:Envelope/soapenv:Body/l3:xyzRequest'">" +
"<Test><xsl:value-of select='"workpackageId'" /></Test>" +
"</xsl:template>" +
"</xsl:stylesheet>");
XDocument XML = XDocument.Parse("<soapenv:Envelope xmlns:soapenv='"http://schemas.xmlsoap.org/soap/envelope/'" xmlns:l3='"http://tempuri.org/l3'">" +
"<soapenv:Header>" +
"<l3:requestType>Valid</l3:requestType>" +
"</soapenv:Header>" +
"<soapenv:Body>" +
"<l3:xyzRequest xsi:schemaLocation='"http://tempuri.org/l3 lds.xsd '" xmlns:xsi='"http://www.w3.org/2001/XMLSchema-instance'">" +
"<workpackageId>126381</workpackageId>" +
"</l3:xyzRequest>" +
"</soapenv:Body>" +
"</soapenv:Envelope>");
XslCompiledTransform xslt = new XslCompiledTransform(false);
StringBuilder sb = new StringBuilder();
xslt.Load(XSL.CreateReader());
using (XmlWriter xw = XmlWriter.Create(sb, xslt.OutputSettings))
{
xslt.Transform(XML.CreateReader(), xw);
}
Console.WriteLine(sb.ToString());
Console.ReadLine();
}
}
}
如果运行该操作,则模板不匹配,并且会得到返回所有节点值的默认行为:Valid<Test xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:l3="http://tempuri.org/l3">126381</Test>
;但是,如果注释掉第21行("<l3:requestType>Valid</l3:requestType>" +
),则模板是匹配的,您将得到预期的结果:<Test xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:l3="http://tempuri.org/l3">126381</Test>
。
编辑2:
哎呀,我刚刚注意到,我在上面发布的第一个结果并不是默认的行为,但它不是格式良好的XML,这就是让我失望的原因。很抱歉,在复制和粘贴时应该仔细看一下!我想现在的问题是:当一个元素包含在SOAP头中时,为什么会返回它的值,尽管它不是XSLT模板中的值?
用于匹配输入中l3:xyzRequest元素的模板可能没有产生结果的最明显的可能原因是:
-
输入可能没有任何l3:xyzRequest元素。如果您显示的输入片段是正确的,那么这不是您的问题。
-
模板上的匹配模式可能与预期元素不匹配;这可能是由于拼写错误的名称、绑定名称空间前缀的错误或XPath表达式的公式化问题造成的。乍一看,这似乎不是你的问题。
-
样式表可能永远不会要求处理器处理该元素。(更具体地说:在它选择的节点中,可能没有xsl:apply-templates指令包含l3:xyzRequest元素。)如果没有完整的样式表,就无法确认这是问题的原因,但也不能排除这种可能性。
你说,如果从输入中删除不同的元素,会导致转换"正常工作"。我猜这意味着在这种情况下,模板确实会从l3:xyzRequest元素产生输出。这表明,基于其他元素的存在或不存在(或值)的一些条件正在影响样式表处理。
我的建议是,开始减少样式表,直到您拥有尽可能小的样式表,它展示了您试图更改的行为(当l3:requestType元素丢失时,"工作正常",当它存在时中断)。当你把它减少到20行左右时,答案要么很明显,要么对一些Stack Overflow阅读器来说相对容易找到。
[附录]一旦将代码中的XML和XSLT从混合在一起的C#中解开,就有了这个XML实例:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:l3="http://tempuri.org/l3">
<soapenv:Header>
<l3:requestType>Valid</l3:requestType>
</soapenv:Header>
<soapenv:Body>
<l3:xyzRequest xsi:schemaLocation="http://tempuri.org/l3 lds.xsd "
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<workpackageId>126381</workpackageId>
</l3:xyzRequest>
</soapenv:Body>
</soapenv:Envelope>
要使用此XSLT:进行处理
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:l3="http://tempuri.org/l3" version="1.0">
<xsl:output method="xml" />
<xsl:template
match="soapenv:Envelope/soapenv:Body/l3:xyzRequest">
<Test><xsl:value-of select="workpackageId"/></Test>
</xsl:template>
</xsl:stylesheet>
在此XML上运行此样式表会产生以下输出:
<?xml version="1.0"?>
Valid
<Test xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:l3="http://tempuri.org/l3">126381</Test>
我不清楚你为什么认为模板不匹配。
字符串"Valid"出现在输出中,因为您没有重写内置的默认模板(通过在元素的子模板上重复出现来处理元素,通过将文本节点复制到输出来处理文本节点)。