Xml XSLT输出冗长而混乱

Xml XSLT输出冗长而混乱,xml,web-services,xslt,xalan,Xml,Web Services,Xslt,Xalan,我开始使用XSLT来临时支持当前1.0版本的Web服务,同时客户机转换到1.1,将旧调用转换为新格式 对于这种更改,我需要更改名称空间,包括一个节点并重命名另一个节点。我是XSLT新手,但在谷歌搜索之后,我想出了一个可行的解决方案,但是它的工作原理和输出看起来很混乱,我不确定它的故障安全性有多高。我想要一些建议来增强它,使它更干净,更易于维护(1.2版需要更多的转换) 输入XML示例(我的SOAP客户端使用限定元素): edir2:作为测试,我用Saxon替换了Xalan,输出就像Michae

我开始使用XSLT来临时支持当前1.0版本的Web服务,同时客户机转换到1.1,将旧调用转换为新格式

对于这种更改,我需要更改名称空间,包括一个节点并重命名另一个节点。我是XSLT新手,但在谷歌搜索之后,我想出了一个可行的解决方案,但是它的工作原理和输出看起来很混乱,我不确定它的故障安全性有多高。我想要一些建议来增强它,使它更干净,更易于维护(1.2版需要更多的转换)

输入XML示例(我的SOAP客户端使用限定元素):



edir2:作为测试,我用Saxon替换了Xalan,输出就像Michael发布的一样好。然而,对于我们已经很大的应用程序来说,它是一个很大的jar,加上它与应用程序的其他部分冲突,因此它更像是一个不稳定因素。我只想把重点放在Xalan上,让它正常工作。

我不确定这是否适合您,因为我使用的是不同的xlst处理器(xsltproc)。 另外,我的原始xslt输出与您的输出并不完全相同

总之:
我主要从xlst中删除了namespace属性,并添加了两倍的名称空间前缀“newns”

试试这个:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:oldns="namespace/1.0"
    xmlns:newns="namespace/1.1"
    version="1.0">

    <xsl:param name="newnsParam">namespace/1.1</xsl:param>

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

    <!-- rename 'g' to 'newName' -->
    <xsl:template match="/oldns:testRequest/oldns:a/oldns:b1/oldns:g">
        <!-- if I don't set it with newns now, it will remain as oldns even after namespace change below -->
        <xsl:element name="newns:newName">
            <xsl:apply-templates select="@*|node()" />
        </xsl:element>
    </xsl:template>

    <!-- add 'newElement' -->
    <xsl:template match="/oldns:testRequest/oldns:a/oldns:b1">
        <!-- same as above, must set as newns now, and this one won't be qualified (why?) -->
        <xsl:element name="newns:b1" >
            <xsl:apply-templates select="@*|node()" />
            <xsl:element name="newns:newElement">NEW_VAL</xsl:element>
        </xsl:element>
    </xsl:template>

    <!-- change namespace, but it makes every node redefine the namespace -->
    <xsl:template match="@oldns:*">
        <xsl:attribute name="newns:{local-name()}">
            <xsl:value-of select="."/>
        </xsl:attribute>
    </xsl:template>
    <xsl:template match="oldns:*">
        <xsl:element name="newns:{local-name()}">
            <xsl:apply-templates select="node()|@*"/>
        </xsl:element>
    </xsl:template>

</xsl:stylesheet>

命名空间/1.1
新谷
它生成以下输出(至少使用xsltproc):


中交
dddd
eeee
新谷
假的
2014-03-01
真的

我很惊讶Xalan竟然会生成所有这些冗余的名称空间声明。以下是用于比较的Saxon输出:

<?xml version="1.0" encoding="UTF-8"?><newns:testRequest xmlns:newns="namespace/1.1">
     <newns:a>
        <b1 xmlns="namespace/1.1">
           <newns:c>cccc</newns:c>
           <newns:d>dddd</newns:d>
           <newns:e>eeee</newns:e>
        <newElement>NEW_VAL</newElement></b1>
        <newns:b2 attr="value">
           <newns:f>false</newns:f>
           <newns:g>2014-03-01</newns:g>
           <newns:h>true</newns:h>
        </newns:b2>
        <newns:b3>
        </newns:b3>
     </newns:a>
  </newns:testRequest>

中交
dddd
eeee
新谷
假的
2014-03-01
真的
如果您想使主要名称空间newns成为默认名称空间,为了进一步减少混乱,可以将
更改为
。这将产生以下输出:

<?xml version="1.0" encoding="UTF-8"?>
<testRequest xmlns="namespace/1.1">
     <a>
        <b1>
           <c>cccc</c>
           <d>dddd</d>
           <e>eeee</e>
        <newElement>NEW_VAL</newElement></b1>
        <b2 attr="value">
           <f>false</f>
           <g>2014-03-01</g>
           <h>true</h>
        </b2>
        <b3>
        </b3>
     </a>
  </testRequest>

中交
dddd
eeee
新谷
假的
2014-03-01
真的
以下是修改后的样式表:

<xsl:stylesheet
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:oldns="namespace/1.0"
    xmlns:newns="namespace/1.1"
    version="1.0">

    <xsl:param name="newnsParam">namespace/1.1</xsl:param>

    <!-- copy all document -->
    <xsl:template match="*">
        <xsl:element name="{local-name()}" namespace="{namespace-uri()}">
            <xsl:apply-templates select="*" />
        </xsl:element>
    </xsl:template>

    <xsl:template match="@*">
        <xsl:copy-of select="."/>
    </xsl:template>

    <!-- rename 'g' to 'newName' -->
    <xsl:template match="/oldns:testRequest/oldns:a/oldns:b1/oldns:g">
        <!-- if I don't set it with newns now, it will remain as oldns even after namespace change below -->
        <xsl:element name="newName" namespace="{$newnsParam}">
            <xsl:apply-templates select="@*|node()" />
        </xsl:element>
    </xsl:template>

    <!-- add 'newElement' -->
    <xsl:template match="/oldns:testRequest/oldns:a/oldns:b1">
        <!-- same as above, must set as newns now, and this one won't be qualified (why?) -->
        <xsl:element name="b1" namespace="{$newnsParam}">
            <xsl:apply-templates select="@*|node()" />
            <xsl:element name="newElement" namespace="{$newnsParam}">NEW_VAL</xsl:element>
        </xsl:element>
    </xsl:template>

    <!-- change namespace, but it makes every node redefine the namespace -->
    <xsl:template match="@oldns:*">
        <xsl:attribute name="newns:{local-name()}" namespace="{$newnsParam}">
            <xsl:value-of select="."/>
        </xsl:attribute>
    </xsl:template>

    <xsl:template match="oldns:*">
        <xsl:element name="{local-name()}" namespace="{$newnsParam}">
            <xsl:apply-templates select="node()|@*"/>
        </xsl:element>
    </xsl:template>

</xsl:stylesheet>

命名空间/1.1
新谷

谢谢你的建议。我以前也尝试过类似的方法,您的建议对我的解析器也不起作用。不过,输出是完美的。我在问题主体中添加了一个例外。谢谢Michael,但是您的建议仍然使每个节点都有一个名称空间声明。这是Xalan配置问题吗?它正在调用堆栈的深处使用,我甚至不确定是否可以配置它。。。经过大量的搜索,没有发现有用的东西。Xalan与JRE捆绑在一起很方便。如果我要迁移到Saxon,这个XSLT不能使用2.0版进行改进吗?后续:厌倦了与Xalan的斗争,最终迁移到了Saxon(这只是因为没有压缩JAR)。现在我的输出正常了。
javax.xml.transform.TransformerException: java.lang.RuntimeException: Namespace for prefix 'newns' has not been declared.
    at com.sun.org.apache.xalan.internal.xsltc.trax.TransformerImpl.transform(TransformerImpl.java:717) ~[na:1.6.0_14]
    at com.sun.org.apache.xalan.internal.xsltc.trax.TransformerImpl.transform(TransformerImpl.java:313) ~[na:1.6.0_14]
    at org.springframework.ws.server.endpoint.interceptor.PayloadTransformingInterceptor.transformMessage(PayloadTransformingInterceptor.java:118) ~[spring-ws-core-2.1.0.RELEASE.jar:na]
    at org.springframework.ws.server.endpoint.interceptor.PayloadTransformingInterceptor.handleRequest(PayloadTransformingInterceptor.java:92) ~[spring-ws-core-2.1.0.RELEASE.jar:na]
    at org.springframework.ws.server.endpoint.interceptor.DelegatingSmartEndpointInterceptor.handleRequest(DelegatingSmartEndpointInterceptor.java:78) ~[spring-ws-core-2.1.0.RELEASE.jar:na]
    at org.springframework.ws.server.MessageDispatcher.dispatch(MessageDispatcher.java:224) [spring-ws-core-2.1.0.RELEASE.jar:na]
    at org.springframework.ws.server.MessageDispatcher.receive(MessageDispatcher.java:173) [spring-ws-core-2.1.0.RELEASE.jar:na]
    at org.springframework.ws.transport.support.WebServiceMessageReceiverObjectSupport.handleConnection(WebServiceMessageReceiverObjectSupport.java:88) [spring-ws-core-2.1.0.RELEASE.jar:na]
    at org.springframework.ws.transport.http.WebServiceMessageReceiverHandlerAdapter.handle(WebServiceMessageReceiverHandlerAdapter.java:59) [spring-ws-core-2.1.0.RELEASE.jar:na]
    at org.springframework.ws.transport.http.MessageDispatcherServlet.doService(MessageDispatcherServlet.java:221) [spring-ws-core-2.1.0.RELEASE.jar:na]
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:882) [org.springframework.web.servlet-3.1.3.RELEASE.jar:3.1.3.RELEASE]
    at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:789) [org.springframework.web.servlet-3.1.3.RELEASE.jar:3.1.3.RELEASE]
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:727) [javax.servlet_1.0.0.0_2-5.jar:2.5]
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:820) [javax.servlet_1.0.0.0_2-5.jar:2.5]
    at weblogic.servlet.internal.StubSecurityHelper$ServletServiceAction.run(StubSecurityHelper.java:227) [weblogic.jar:10.3.2.0]
    at weblogic.servlet.internal.StubSecurityHelper.invokeServlet(StubSecurityHelper.java:125) [weblogic.jar:10.3.2.0]
    at weblogic.servlet.internal.ServletStubImpl.execute(ServletStubImpl.java:292) [weblogic.jar:10.3.2.0]
    at weblogic.servlet.internal.ServletStubImpl.execute(ServletStubImpl.java:175) [weblogic.jar:10.3.2.0]
    at weblogic.servlet.internal.WebAppServletContext$ServletInvocationAction.run(WebAppServletContext.java:3591) [weblogic.jar:10.3.2.0]
    at weblogic.security.acl.internal.AuthenticatedSubject.doAs(AuthenticatedSubject.java:321) [com.bea.core.weblogic.security.identity_1.1.2.0.jar:1.1.2.0]
    at weblogic.security.service.SecurityManager.runAs(SecurityManager.java:121) [com.bea.core.weblogic.security.wls_1.0.0.0_5-2-0-0.jar:5.2.0.0]
    at weblogic.servlet.internal.WebAppServletContext.securedExecute(WebAppServletContext.java:2202) [weblogic.jar:10.3.2.0]
    at weblogic.servlet.internal.WebAppServletContext.execute(WebAppServletContext.java:2108) [weblogic.jar:10.3.2.0]
    at weblogic.servlet.internal.ServletRequestImpl.run(ServletRequestImpl.java:1432) [weblogic.jar:10.3.2.0]
    at weblogic.work.ExecuteThread.execute(ExecuteThread.java:201) [com.bea.core.weblogic.workmanager_1.7.0.0.jar:1.7.0.0]
    at weblogic.work.ExecuteThread.run(ExecuteThread.java:173) [com.bea.core.weblogic.workmanager_1.7.0.0.jar:1.7.0.0]
Caused by: java.lang.RuntimeException: Namespace for prefix 'newns' has not been declared.
    at com.sun.org.apache.xalan.internal.xsltc.runtime.BasisLibrary.runTimeError(BasisLibrary.java:1518) ~[na:1.6.0_14]
    at com.sun.org.apache.xalan.internal.xsltc.runtime.BasisLibrary.runTimeError(BasisLibrary.java:1522) ~[na:1.6.0_14]
    at com.sun.org.apache.xalan.internal.xsltc.runtime.BasisLibrary.startXslElement(BasisLibrary.java:1408) ~[na:1.6.0_14]
    at transformation_1_0_to_1_1.template$dot$4() ~[na:na]
    at transformation_1_0_to_1_1.applyTemplates() ~[na:na]
    at transformation_1_0_to_1_1.applyTemplates() ~[na:na]
    at transformation_1_0_to_1_1.transform() ~[na:na]
    at com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet.transform(AbstractTranslet.java:602) ~[na:1.6.0_14]
    at com.sun.org.apache.xalan.internal.xsltc.trax.TransformerImpl.transform(TransformerImpl.java:710) ~[na:1.6.0_14]
    ... 25 common frames omitted
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:oldns="namespace/1.0"
    xmlns:newns="namespace/1.1"
    version="1.0">

    <xsl:param name="newnsParam">namespace/1.1</xsl:param>

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

    <!-- rename 'g' to 'newName' -->
    <xsl:template match="/oldns:testRequest/oldns:a/oldns:b1/oldns:g">
        <!-- if I don't set it with newns now, it will remain as oldns even after namespace change below -->
        <xsl:element name="newns:newName">
            <xsl:apply-templates select="@*|node()" />
        </xsl:element>
    </xsl:template>

    <!-- add 'newElement' -->
    <xsl:template match="/oldns:testRequest/oldns:a/oldns:b1">
        <!-- same as above, must set as newns now, and this one won't be qualified (why?) -->
        <xsl:element name="newns:b1" >
            <xsl:apply-templates select="@*|node()" />
            <xsl:element name="newns:newElement">NEW_VAL</xsl:element>
        </xsl:element>
    </xsl:template>

    <!-- change namespace, but it makes every node redefine the namespace -->
    <xsl:template match="@oldns:*">
        <xsl:attribute name="newns:{local-name()}">
            <xsl:value-of select="."/>
        </xsl:attribute>
    </xsl:template>
    <xsl:template match="oldns:*">
        <xsl:element name="newns:{local-name()}">
            <xsl:apply-templates select="node()|@*"/>
        </xsl:element>
    </xsl:template>

</xsl:stylesheet>
<?xml version="1.0"?>
<newns:testRequest xmlns:newns="namespace/1.1">
     <newns:a>
        <newns:b1>
           <newns:c>cccc</newns:c>
           <newns:d>dddd</newns:d>
           <newns:e>eeee</newns:e>
        <newns:newElement>NEW_VAL</newns:newElement></newns:b1>
        <newns:b2 attr="value">
           <newns:f>false</newns:f>
           <newns:g>2014-03-01</newns:g>
           <newns:h>true</newns:h>
        </newns:b2>
        <newns:b3>
        </newns:b3>
     </newns:a>
  </newns:testRequest>
<?xml version="1.0" encoding="UTF-8"?><newns:testRequest xmlns:newns="namespace/1.1">
     <newns:a>
        <b1 xmlns="namespace/1.1">
           <newns:c>cccc</newns:c>
           <newns:d>dddd</newns:d>
           <newns:e>eeee</newns:e>
        <newElement>NEW_VAL</newElement></b1>
        <newns:b2 attr="value">
           <newns:f>false</newns:f>
           <newns:g>2014-03-01</newns:g>
           <newns:h>true</newns:h>
        </newns:b2>
        <newns:b3>
        </newns:b3>
     </newns:a>
  </newns:testRequest>
<?xml version="1.0" encoding="UTF-8"?>
<testRequest xmlns="namespace/1.1">
     <a>
        <b1>
           <c>cccc</c>
           <d>dddd</d>
           <e>eeee</e>
        <newElement>NEW_VAL</newElement></b1>
        <b2 attr="value">
           <f>false</f>
           <g>2014-03-01</g>
           <h>true</h>
        </b2>
        <b3>
        </b3>
     </a>
  </testRequest>
<xsl:stylesheet
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:oldns="namespace/1.0"
    xmlns:newns="namespace/1.1"
    version="1.0">

    <xsl:param name="newnsParam">namespace/1.1</xsl:param>

    <!-- copy all document -->
    <xsl:template match="*">
        <xsl:element name="{local-name()}" namespace="{namespace-uri()}">
            <xsl:apply-templates select="*" />
        </xsl:element>
    </xsl:template>

    <xsl:template match="@*">
        <xsl:copy-of select="."/>
    </xsl:template>

    <!-- rename 'g' to 'newName' -->
    <xsl:template match="/oldns:testRequest/oldns:a/oldns:b1/oldns:g">
        <!-- if I don't set it with newns now, it will remain as oldns even after namespace change below -->
        <xsl:element name="newName" namespace="{$newnsParam}">
            <xsl:apply-templates select="@*|node()" />
        </xsl:element>
    </xsl:template>

    <!-- add 'newElement' -->
    <xsl:template match="/oldns:testRequest/oldns:a/oldns:b1">
        <!-- same as above, must set as newns now, and this one won't be qualified (why?) -->
        <xsl:element name="b1" namespace="{$newnsParam}">
            <xsl:apply-templates select="@*|node()" />
            <xsl:element name="newElement" namespace="{$newnsParam}">NEW_VAL</xsl:element>
        </xsl:element>
    </xsl:template>

    <!-- change namespace, but it makes every node redefine the namespace -->
    <xsl:template match="@oldns:*">
        <xsl:attribute name="newns:{local-name()}" namespace="{$newnsParam}">
            <xsl:value-of select="."/>
        </xsl:attribute>
    </xsl:template>

    <xsl:template match="oldns:*">
        <xsl:element name="{local-name()}" namespace="{$newnsParam}">
            <xsl:apply-templates select="node()|@*"/>
        </xsl:element>
    </xsl:template>

</xsl:stylesheet>