我正在尝试将所有子节点复制到特定节点,除了少数几个。一直无法让它工作?有什么指示我做错了什么吗?
使用此 XML:
<ns0:Envelope xmlns:ns0="http://schemas.xmlsoap.org/soap/envelope/">
<ns0:Header>
<wsse:Sec xmlns:wsse="http://docs.x.org/wsse/">
<saml:Ass xmlns:saml="http://docs.x.org/saml/">
<ds:Sign xmlns:ds="http://docs.x.org/ds/">
<ds:SignVal>SignatureValue</ds:SignVal>
</ds:Sign>
<saml:subj>SubjectValue</saml:subj>
</saml:Ass>
</wsse:Sec>
<To>http://localhost:8080/Test/</To>
<Action>SendTest</Action>
</ns0:Header>
<ns0:Body>...</ns0:Body>
</ns0:Envelope>
想要的结果是只获取 Sec 标签和所有子项:
<wsse:Sec xmlns:wsse="http://docs.x.org/wsse/">
<saml:Ass xmlns:saml="http://docs.x.org/saml/">
<ds:Sign xmlns:ds="http://docs.x.org/ds/">
<ds:SignVal>SignatureValue</ds:SignVal>
</ds:Sign>
<saml:subj>SubjectValue</saml:subj>
</saml:Ass>
</wsse:Sec>
我已经尝试了许多XSL,包括:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" encoding="utf-8" indent="yes"/>
<xsl:template match="Header">
<xsl:copy-of select="*"/>
</xsl:template>
<!-- Exclude these -->
<xsl:template match="To" />
<xsl:template match="Action" />
</xsl:stylesheet>
结果是我得到了值但没有标签...
您尚未考虑 XSLT 中的命名空间。在 XML 中,Header
位于命名空间http://schemas.xmlsoap.org/soap/envelope/
中,但 XSLT 尝试匹配没有命名空间中的Header
。
您需要在 XSLT 中声明命名空间,并在模板匹配中使用它们
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ns0="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:wsse="http://docs.x.org/wsse/">
<xsl:output method="xml" encoding="utf-8" indent="yes"/>
<xsl:template match="ns0:Header">
<xsl:copy-of select="wsse:Sec"/>
</xsl:template>
<xsl:template match="ns0:Body" />
</xsl:stylesheet>
请注意,此 XSLT 不需要与"To"和"Action"匹配的模板,因为使用此方法显式复制wsse:Sec
。但是,您确实需要模板以确保不会选取ns0:Body
中的任何测试。
另一种方法是使用标识模板,然后您将拥有要排除To
和Action
(和Body
)的模板
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ns0="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:wsse="http://docs.x.org/wsse/">
<xsl:output method="xml" encoding="utf-8" indent="yes"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="ns0:Envelope|ns0:Header">
<xsl:apply-templates />
</xsl:template>
<!-- Exclude these -->
<xsl:template match="ns0:Body|To|Action" />
</xsl:stylesheet>
请注意,有一个ns0:Envelope
和ns0:Header
匹配的模板,因为尽管您不需要这些元素本身,但确实需要处理子节点。
将 XSLT 2 或 3 与
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:wsse="http://docs.x.org/wsse/"
exclude-result-prefixes="#all"
version="3.0">
<xsl:template match="/">
<xsl:copy-of select="//wsse:Sec" copy-namespaces="no"/>
</xsl:template>
</xsl:stylesheet>
要使用简单的复制指令获取发布的结果:https://xsltfiddle.liberty-development.net/bnnZVw
在 XSLT 1 中,副本将始终复制作用域内命名空间xmlns:ns0="http://schemas.xmlsoap.org/soap/envelope/"
因此,要将其从结果中删除,您需要通过某种转换来运行代码,剥离作用域内的命名空间(元素本身除外):
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:wsse="http://docs.x.org/wsse/"
exclude-result-prefixes="wsse"
version="1.0">
<xsl:template match="@*">
<xsl:attribute name="{name()}" namespace="{namespace-uri()}">
<xsl:value-of select="."/>
</xsl:attribute>
</xsl:template>
<xsl:template match="*">
<xsl:element name="{name()}" namespace="{namespace-uri()}">
<xsl:apply-templates select="@* | node()"/>
</xsl:element>
</xsl:template>
<xsl:template match="/">
<xsl:apply-templates select="//wsse:Sec"/>
</xsl:template>
</xsl:stylesheet>
https://xsltfiddle.liberty-development.net/bnnZVw/1