0

我对 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。

4

2 回答 2

2

这个问题确实与命名空间有关。在原始 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”实际上可以是任何东西。必须与 XML 中的 URI 匹配的是 URI“ http://new.webservice.namespace ”。

此外,对于您输出的任何新元素,如果您希望它们成为名称空间的一部分,您可以在它们前面加上名称空间前缀,或者您可以在 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>
于 2013-10-18T12:03:17.220 回答
0

这个 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>
于 2013-10-18T12:05:22.760 回答