2017-07-31 52 views
0

我有一个关于将多个节点合并到一个节点的问题。但我无法弄清楚如何做到这一点。将多个字段合并为一个使用xslt

我有下面的XML文件:

<soap:Envelope xmlns:http="http://schemas.xmlsoap.org/wsdl/http/" 
       xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/" 
       xmlns:s1="http://microsoft.com/wsdl/types/" 
       xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/" 
       xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" 
       xmlns:tm="http://microsoft.com/wsdl/mime/textMatching/"> 
    <soap:Body> 
     <RetrieveTicketUpdatesResponse> 
      <RetrieveTicketUpdatesResult> 
       <TicketUpdates> 
        <TicketUpdate> 
         <FreeFields> 
          <FreeField> 
           <FreeFieldID>9876</FreeFieldID> 
           <Value>Yes</Value> 
          </FreeField> 
         </FreeFields> 
         <FreeFields> 
          <FreeField> 
           <FreeFieldID>8765</FreeFieldID> 
           <Value>Fiber</Value> 
          </FreeField> 
         </FreeFields> 
         <Id>1234</ticketId> 
         <Status>New</status> 
        </TicketUpdate> 
        <TicketUpdate> 
         <TicketUpdate> 
         <FreeFields> 
          <FreeField> 
           <FreeFieldID>6823</FreeFieldID> 
           <Value>No</Value> 
          </FreeField> 
         </FreeFields> 
         <FreeFields> 
          <FreeField> 
           <FreeFieldID>3453</FreeFieldID> 
           <Value>Fiber</Value> 
          </FreeField> 
         </FreeFields> 
         <Id>2343</ticketId> 
         <Status>Update</status> 
        </TicketUpdate> 
       </TicketUpdates> 
      </RetrieveTicketUpdatesResult> 
     </RetrieveTicketUpdatesResponse> 
    </soap:Body> 
</soap:Envelope> 

而且我想给FreeFields节点合并成1个节点像下面并创建以下的输出:

<soap:Envelope xmlns:http="http://schemas.xmlsoap.org/wsdl/http/" 
       xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/" 
       xmlns:s1="http://microsoft.com/wsdl/types/" 
       xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/" 
       xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" 
       xmlns:tm="http://microsoft.com/wsdl/mime/textMatching/"> 
    <soap:Body> 
     <RetrieveTicketUpdatesResponse> 
      <RetrieveTicketUpdatesResult> 
       <TicketUpdates> 
        <TicketUpdate> 
         <FreeFields> 
          <FreeField> 
           <FreeFieldID>9876</FreeFieldID> 
           <Value>Yes</Value> 
          </FreeField> 
          <FreeField> 
           <FreeFieldID>8765</FreeFieldID> 
           <Value>Fiber</Value> 
          </FreeField> 
          <FreeField> 
           <FreeFieldID>7654</FreeFieldID> 
           <Value>https://www.stackoverflow.com</Value> 
          </FreeField> 
         </FreeFields> 
         <Id>1234</ticketId> 
         <Status>New</status> 
        </TicketUpdate> 
        <TicketUpdate> 
         <TicketUpdate> 
         <FreeFields> 
          <FreeField> 
           <FreeFieldID>6823</FreeFieldID> 
           <Value>No</Value> 
          </FreeField> 
          <FreeField> 
           <FreeFieldID>3453</FreeFieldID> 
           <Value>Fiber</Value> 
          </FreeField> 
          <FreeField> 
           <FreeFieldID>8563</FreeFieldID> 
           <Value>https://www.stackexchange.com</Value> 
          </FreeField> 
         </FreeFields> 
         <Id>2343</ticketId> 
         <Status>Update</status> 
        </TicketUpdate> 
       </TicketUpdates> 
      </RetrieveTicketUpdatesResult> 
     </RetrieveTicketUpdatesResponse> 
    </soap:Body> 
</soap:Envelope> 

我试图用一个xsl:for-each。并将其复制到一个新的列表中,但我无法弄清楚如何完成此操作。 有人能帮我一个例子吗? 我试着用Google搜索解决方案,但无法找到解决方案。

更新1 这是我使用

<?xml version="1.0" encoding="UTF-8" standalone="yes"?> 
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:http="http://schemas.xmlsoap.org/wsdl/http/" xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/" xmlns:s1="http://microsoft.com/wsdl/types/" xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:tm="http://microsoft.com/wsdl/mime/textMatching/" version="1.0"> 

    <xsl:output encoding="utf-8" indent="yes" method="xml" omit-xml-declaration="yes" /> 

    <!-- Stylesheet to inject namespaces into a document in specific places --> 
    <xsl:template match="/"> 
    <soap:Envelope> 
     <soap:Body> 
     <RetrieveTicketUpdatesResponse> 

      <xsl:choose> 
      <!-- Handle 'Root' wrapper added by JSON to XML policy --> 
      <xsl:when test="normalize-space(/Root)"> 
       <RetrieveTicketUpdatesResult> 
       <xsl:apply-templates select="node()|@*" /> 
       </RetrieveTicketUpdatesResult> 
      </xsl:when> 

      <!-- If the root element is not what was in the schema, add it --> 
      <xsl:when test="not(normalize-space(/RetrieveTicketUpdates))"> 
       <RetrieveTicketUpdatesResult> 
       <xsl:apply-templates select="node()|@*" /> 
       </RetrieveTicketUpdatesResult> 
      </xsl:when> 
      <!-- everything checks out, just copy the xml--> 
      <xsl:otherwise> 
       <xsl:apply-templates select="node()|@*" /> 
      </xsl:otherwise> 
      </xsl:choose> 
     </RetrieveTicketUpdatesResponse> 
     </soap:Body> 
    </soap:Envelope> 
    </xsl:template> 

    <xsl:template match="@*|node()" name="identity"> 
    <xsl:copy> 
     <xsl:apply-templates select="@*|node()" /> 
    </xsl:copy> 
    </xsl:template> 

    <xsl:template match="/FreeFields/*/FreeField" name="copy-freefields"> 
    <xsl:element name="{local-name()}"> 
     <xsl:copy-of select="*" /> 
     <xsl:apply-templates select="node()|@*" /> 
    </xsl:element> 
    </xsl:template> 

    <xsl:template match="/Root/*" name="copy-root"> 
    <xsl:element name="{local-name()}"> 
     <xsl:copy-of select="namespace::*" /> 
     <xsl:apply-templates select="node()|@*" /> 
    </xsl:element> 
    </xsl:template> 

    <xsl:template match="*[not(local-name()='Root') and not(local-name()='Array')]" name="copy-all"> 
    <xsl:element name="{local-name()}"> 
     <xsl:copy-of select="namespace::*" /> 
     <xsl:apply-templates select="node()|@*" /> 
    </xsl:element> 
    </xsl:template> 

    <!-- template to copy the rest of the nodes --> 
    <xsl:template match="comment() | processing-instruction()"> 
    <xsl:copy /> 
    </xsl:template> 
</xsl:stylesheet> 
+0

请发布您的尝试,以便我们可以修复它,而不必从头为您编写代码。同时说明如果使用XSLT 1.0或2.0。 –

+0

另请注意,您向我们显示的输入和输出都缺少一个将'soap'前缀绑定到名称空间URI的名称空间声明。 –

回答

1

试试下面的脚本XSLT:

<?xml version="1.0" encoding="UTF-8" ?> 
<xsl:transform version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:soap="http://schemas.xmlsoap.org/soap"> 
    <xsl:output method="xml" omit-xml-declaration="yes" encoding="UTF-8" indent="yes" /> 
    <xsl:strip-space elements="*"/> 

    <xsl:template match="TicketUpdate"> 
    <xsl:copy> 
     <FreeFields> 
     <xsl:copy-of select="FreeFields/FreeField"/> 
     </FreeFields> 
     <xsl:apply-templates select="*[name() != 'FreeFields']"/> 
    </xsl:copy> 
    </xsl:template> 

    <xsl:template match="@*|node()"> 
    <xsl:copy><xsl:apply-templates select="@*|node()"/></xsl:copy> 
    </xsl:template> 
</xsl:transform> 

你也纠正源XML一些错误。

+0

Tnx! :)我的源代码XML更大,剥离了许多额外的节点。我想我没有正确编辑它。你的解决方案就像一个魅力 – MFasseur