为什么在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模板中的值?

为什么在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"出现在输出中,因为您没有重写内置的默认模板(通过在元素的子模板上重复出现来处理元素,通过将文本节点复制到输出来处理文本节点)。