XSL 转换中的命名空间出现错误结果



我在xsl转换方面遇到了问题。我没有得到我期望的结果,我看不出出了什么问题。我认为问题与命名空间有关。你可以帮我吗?

这是我的服务将收到的 xml。我想将多值元素分离到一些新节点。

<soap-env:Envelope xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
   <soap-env:Header/>
   <soap-env:Body>
      <testService facade="Test" xmlns="http://new.webservice.namespace">
         <input>
            <Data1>Data 1</Data1>
            <Data2>Data 2</Data2>
            <ParamResponses>
               <ParamResponse>
                  <Name>DATAONE</Name>
                  <ValParam>Text 1</ValParam>
               </ParamResponse>
               <ParamResponse>
                  <Name>DATATWO</Name>
                  <ValParam>Text 2</ValParam>
               </ParamResponse>
               <ParamResponse>
                  <Name>MULTIVALUED</Name>
                  <ValParam>001</ValParam>
                  <ValParam>002</ValParam>
               </ParamResponse>
               <ParamResponse>
                  <Name>DATATHREE</Name>
                  <ValParam>Text 3</ValParam>
               </ParamResponse>
            </ParamResponses>
         </input>
      </testService>
   </soap-env:Body>
</soap-env:Envelope>

这是我正在应用的 xslt

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
   <xsl:output method="xml" indent="yes"/>
    <xsl:template match="@facade">
        <xsl:attribute name="facade">
               <xsl:text>FacadeReplaced</xsl:text>
            </xsl:attribute>
    </xsl:template>
   <xsl:template match="input/ParamResponses">
      <ParamResponses>
         <xsl:for-each select="ParamResponse[Name!='MULTIVALUED']">
            <ParamResponse>
               <xsl:copy>
         <xsl:apply-templates select="@* | node()"/>
      </xsl:copy>
            </ParamResponse>
         </xsl:for-each>
      </ParamResponses>
      <MultiValueParamResponses>
         <MultiValueParamResponse>
            <Name>MULTIVALUED</Name>
           <xsl:variable name="items" select="//input/ParamResponses/ParamResponse[Name='MULTIVALUED']/ValParam"/>
            <ValueList>
               <xsl:for-each select="$items">
                  <value>
                     <xsl:value-of select="."/>
                  </value>
               </xsl:for-each>
            </ValueList>
         </MultiValueParamResponse>
      </MultiValueParamResponses>
   </xsl:template>
   <xsl:template match="@* | node()">
      <xsl:copy>
         <xsl:apply-templates select="@* | node()"/>
      </xsl:copy>
   </xsl:template>
</xsl:stylesheet>

这是我得到的:

<?xml version="1.0" encoding="UTF-16"?>
<soap-env:Envelope xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <soap-env:Header/>
    <soap-env:Body>
        <testService facade="FacadeReplaced" xmlns="http://new.webservice.namespace">
            <input>
                <Data1>Data 1</Data1>
                <Data2>Data 2</Data2>
                <ParamResponses>
                    <ParamResponse>
                        <Name>DATAONE</Name>
                        <ValParam>Text 1</ValParam>
                    </ParamResponse>
                    <ParamResponse>
                        <Name>DATATWO</Name>
                        <ValParam>Text 2</ValParam>
                    </ParamResponse>
                    <ParamResponse>
                        <Name>MULTIVALUED</Name>
                        <ValParam>001</ValParam>
                        <ValParam>002</ValParam>
                    </ParamResponse>
                    <ParamResponse>
                        <Name>DATATHREE</Name>
                        <ValParam>Text 3</ValParam>
                    </ParamResponse>
                </ParamResponses>
            </input>
        </testService>
    </soap-env:Body>
</soap-env:Envelope>

但这就是我想要获得的:

<?xml version="1.0" encoding="UTF-16"?>
<soap-env:Envelope xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <soap-env:Header/>
    <soap-env:Body>
        <testService facade="FacadeReplaced" xmlns="http://new.webservice.namespace">
            <input>
                <Data1>Data 1</Data1>
                <Data2>Data 2</Data2>
                <ParamResponses>
                    <ParamResponse>
                        <ParamResponse>
                            <Name>DATAONE</Name>
                            <ValParam>Text 1</ValParam>
                        </ParamResponse>
                    </ParamResponse>
                    <ParamResponse>
                        <ParamResponse>
                            <Name>DATATWO</Name>
                            <ValParam>Text 2</ValParam>
                        </ParamResponse>
                    </ParamResponse>
                    <ParamResponse>
                        <ParamResponse>
                            <Name>DATATHREE</Name>
                            <ValParam>Text 3</ValParam>
                        </ParamResponse>
                    </ParamResponse>
                </ParamResponses>
                <MultiValueParamResponses>
                    <MultiValueParamResponse>
                        <Name>MULTIVALUED</Name>
                        <ValueList>
                            <value>001</value>
                            <value>002</value>
                        </ValueList>
                    </MultiValueParamResponse>
                </MultiValueParamResponses>
            </input>
        </testService>
    </soap-env:Body>
</soap-env:Envelope>

如果我将 xmlns 添加到元素输入中,我已经正确获得了它,但这不是我将通过 Web 服务接收的内容。

转换应该是 XSLT 1.0。

这个问题确实与命名空间有关。在原始 XML 中,您有此行

 <testService facade="Test" xmlns="http://new.webservice.namespace">

这是 testService 元素,它下面的所有元素都将成为"http://new.webservice.namespace"的一部分(除非被其他命名空间声明覆盖)。

但是,在 XSLT 中,没有提及此命名空间。这意味着当你有这样的表达式时...

<xsl:template match="input/ParamResponses">

它正在寻找属于 NO 命名空间的元素。由于源 XML 在命名空间中具有元素,因此此模板不会匹配任何内容。在您的情况下,标识模板将改为匹配,从而导致输出与输入相同。

因此,您需要做的是在 XSLT 中声明命名空间

<xsl:stylesheet version="1.0" 
     xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
     xmlns:ns="http://new.webservice.namespace">

然后,每当从输入 XML 引用元素时,都必须使用相关的命名空间前缀

<xsl:template match="ns:input/ns:ParamResponses">

请注意,命名空间前缀"ns"实际上可以是任何内容。URI"http://new.webservice.namespace"必须与 XML 中的 URI 匹配。

此外,对于输出的任何新元素,如果希望这些元素成为命名空间的一部分,则可以使用命名空间前缀作为前缀,也可以在 XSLT 中声明默认命名空间,这将应用于输出的任何没有前缀的新元素

试试这个 XSLT

<xsl:stylesheet version="1.0" 
     xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
     xmlns:ns="http://new.webservice.namespace"
     xmlns="http://new.webservice.namespace">
   <xsl:output method="xml" indent="yes"/>
    <xsl:template match="@facade">
        <xsl:attribute name="facade">
               <xsl:text>FacadeReplaced</xsl:text>
            </xsl:attribute>
    </xsl:template>
   <xsl:template match="ns:input/ns:ParamResponses">
      <ParamResponses>
         <xsl:for-each select="ns:ParamResponse[ns:Name!='MULTIVALUED']">
            <ParamResponse>
               <xsl:copy>
         <xsl:apply-templates select="@* | node()"/>
      </xsl:copy>
            </ParamResponse>
         </xsl:for-each>
      </ParamResponses>
      <MultiValueParamResponses>
         <MultiValueParamResponse>
            <Name>MULTIVALUED</Name>
           <xsl:variable name="items" select="//ns:input/ns:ParamResponses/ns:ParamResponse[ns:Name='MULTIVALUED']/ns:ValParam"/>
            <ValueList>
               <xsl:for-each select="$items">
                  <value>
                     <xsl:value-of select="."/>
                  </value>
               </xsl:for-each>
            </ValueList>
         </MultiValueParamResponse>
      </MultiValueParamResponses>
   </xsl:template>
   <xsl:template match="@* | node()">
      <xsl:copy>
         <xsl:apply-templates select="@* | node()"/>
      </xsl:copy>
   </xsl:template>
</xsl:stylesheet>

此 XSLT 样式表:

<!-- Define a 'web' namespace that is equal to the default namespace in your input.
     This way, we can match elements in your input (like ParamResponse, Name) 
     that belong to this namespace. 
     We also need to define the same namespace as the default, so that we can
     exclude it from elements we output. -->
<xsl:stylesheet version="1.0"
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:web="http://new.webservice.namespace"
                xmlns="http://new.webservice.namespace"
                exclude-result-prefixes="web #default">
  <xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
  <xsl:strip-space elements="*"/>
  <!-- The identity transform: outputs identical XML to the input, in the
       absence of template overrides. -->
  <xsl:template match="@* | node()">
    <xsl:copy>
      <xsl:apply-templates select="@* | node()"/>
    </xsl:copy>
  </xsl:template>
  <xsl:template match="@facade">
    <xsl:attribute name="facade">
      <xsl:text>FacadeReplaced</xsl:text>
    </xsl:attribute>
  </xsl:template>
  <!-- Match ParamResponse elements in the web namespace. -->
  <xsl:template match="web:ParamResponses">
    <!-- Output the single-valued ParamResponse elements first. These will
         match the identity transform and just get copied out. -->
    <xsl:apply-templates select="web:ParamResponse[not(web:Name='MULTIVALUED')]"/>
    <!-- Output a new MultiValueParamResponses element and apply-templates to
         all ParamResponse elements with a MULTIVALUED Name element. -->
    <MultiValueParamResponses>
      <xsl:apply-templates select="web:ParamResponse[web:Name='MULTIVALUED']"/>
    </MultiValueParamResponses>
  </xsl:template>
  <!-- For the MULTIVALUED ParamResponse elements, change the element name
       and start a new ValueList element. -->
  <xsl:template match="web:ParamResponse[web:Name='MULTIVALUED']">
    <MultiValueParamResponse>
      <xsl:apply-templates select="web:Name" />
      <ValueList>
        <xsl:apply-templates select="web:ValParam" mode="multi"/>
      </ValueList>
    </MultiValueParamResponse>
  </xsl:template>
  <!-- Change the name of the ValParam elements for MULTIVALUED
       ParamResponse elements. -->
  <xsl:template match="web:ValParam" mode="multi">
    <value>
      <xsl:value-of select="."/>
    </value>
  </xsl:template>
</xsl:stylesheet>

应用于输入时生成以下输出 XML:

<soap-env:Envelope xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <soap-env:Header />
  <soap-env:Body>
    <testService facade="FacadeReplaced" xmlns="http://new.webservice.namespace">
      <input>
        <Data1>Data 1</Data1>
        <Data2>Data 2</Data2>
        <ParamResponse>
          <Name>DATAONE</Name>
          <ValParam>Text 1</ValParam>
        </ParamResponse>
        <ParamResponse>
          <Name>DATATWO</Name>
          <ValParam>Text 2</ValParam>
        </ParamResponse>
        <ParamResponse>
          <Name>DATATHREE</Name>
          <ValParam>Text 3</ValParam>
        </ParamResponse>
        <MultiValueParamResponses>
          <MultiValueParamResponse>
            <Name>MULTIVALUED</Name>
            <ValueList>
              <value>001</value>
              <value>002</value>
            </ValueList>
          </MultiValueParamResponse>
        </MultiValueParamResponses>
      </input>
    </testService>
  </soap-env:Body>
</soap-env:Envelope>

相关内容

  • 没有找到相关文章