在基于XSL的转换后删除空的xmlns元素

top*_*erg 2 xml xslt transformation xml-namespaces

最近,我一直在使用数据转换工具,该工具使用XSL来修改输入数据的格式.我最近一直遇到命名空间问题,现在我遇到了一个新问题,由上一个问题的解决方案引起.

正确的xmlns存储在父元素中,但第一个子元素(唯一的第一级子节点)包含一个属性xmlns="".我发现了一些类似的问题,但实现的问题/方法不同,足以阻止我直接应用更改.有谁知道如何阻止该属性应用于子数据?我想过要沿着我之前走过的路径(通过序列化XML然后进行字符串操作来修复它),但是所需的序列化功能只存在于xpath 3中,而我使用的转换服务器只支持最多xpath 2,遗憾的是我没有发言权:(

我正在使用Map Force来构建XSL转换,因此,不能简单地编辑XSL(因为它将被map force覆盖),但我相信我可以将XSL更改应用于Map Force.

XSLT的一个小部件

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:core="http://www.altova.com/MapForce/UDF/core" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions" exclude-result-prefixes="core xs fn">
    <xsl:template name="core:firstCharacter">
        ...
    </xsl:template>
    <xsl:template name="core:tokenize-by-length-internal">
        ...
    </xsl:template>
    <xsl:output method="xml" encoding="UTF-8" byte-order-mark="no" indent="yes"/>
    <xsl:template match="/">
        <xsl:variable name="var1_SwiftMessages" as="node()?" select="SwiftMessages"/>
        <xformResult xmlns="urn:...">
            <xsl:attribute name="xsi:schemaLocation" namespace="http://www.w3.org/2001/XMLSchema-instance" select="'urn:... OutputInterface/xformResult.xsd'"/>
            <xformResultRecord>
                <xformResultData>
                    <Document>
                        <!-- REMAINDER OF FAIRLY STANDARD CODE -->
                    </Document>
                </xformResultData>
            </xformResultRecord>
        </xformResult>
    </xsl:template>
Run Code Online (Sandbox Code Playgroud)

urn:...是对输出文件规范的引用,是输出文件xformResult.xsd的Schema.

然后将变换器XML文件发送回处理程序程序,然后将其中的所有元素<xformResultData>输出到文件中.这就是问题所在.输出文件如下所示:

<?xml version="1.0" encoding="UTF-8"?>
<Document xmlns="urn:..." xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <Cstmr xmlns="">
        <!-- REMAINDER OF GENERATED XML -->
    </Cstmr>
</Document>
Run Code Online (Sandbox Code Playgroud)

如您所见,Document(Cstmr)的第一级子xmlns=""元素已通过变换器输出添加到元素中.当我用Map Force测试它时,这不包括在内,但它在xform工具的输出中.xform工具基于SAXON,对它的调用是相当标准的XML函数.

Ian*_*rts 6

命名空间声明不是属性,即使它们看起来相同.如果您xmlns=""出现在输出中的元素上,那么这意味着您在已经生效的默认命名空间的位置向树中添加了没有命名空间的元素.为了输出这样的结构,序列化器必须使用默认值来反对xmlns="".

要解决此问题,您需要在正确的命名空间中创建元素以开始.例如,假设您的输入XML类似于

<example xmlns="http://example.com">
  <child1/>
</example>
Run Code Online (Sandbox Code Playgroud)

并且要替换child1使用child2.下列:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  <xsl:template match="@*|node()">
    <xsl:copy><xsl:apply-templates select="@*|node()" /></xsl:copy>
  </xsl:template>

  <!-- replace children of the document element with child2 -->
  <xsl:template match="/*/*">
    <child2 /><!-- child2 is in no namespace -->
  </xsl:template>
</xsl:stylesheet>
Run Code Online (Sandbox Code Playgroud)

会产生像你所看到的那样的结果

<example xmlns="http://example.com">
  <child2 xmlns=""/>
</example>
Run Code Online (Sandbox Code Playgroud)

因为样式表在没有命名空间的情况下创建了child2元素.但是如果你添加xmlns="http://example.com"样式表:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
                xmlns="http://example.com">
  <xsl:template match="@*|node()">
    <xsl:copy><xsl:apply-templates select="@*|node()" /></xsl:copy>
  </xsl:template>

  <!-- replace children of the document element with child2 -->
  <xsl:template match="/*/*">
    <child2 /><!-- child2 is now in the http://example.com namespace -->
  </xsl:template>
</xsl:stylesheet>
Run Code Online (Sandbox Code Playgroud)

那么它会产生正确的结果

<example xmlns="http://example.com">
  <child2 />
</example>
Run Code Online (Sandbox Code Playgroud)

如果您不想将默认声明添加到整个样式表,您可以在负责创建输出元素的模板上或者实际上在元素本身上将其本地化,例如

  <xsl:template match="/*/*" xmlns="http://example.com">
    <child2/>
  </xsl:template>
Run Code Online (Sandbox Code Playgroud)

编辑:参考您的具体示例:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:core="http://www.altova.com/MapForce/UDF/core" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions" exclude-result-prefixes="core xs fn">
    <xsl:template name="core:firstCharacter">
        ...
    </xsl:template>
    <xsl:template name="core:tokenize-by-length-internal">
        ...
    </xsl:template>
    <xsl:output method="xml" encoding="UTF-8" byte-order-mark="no" indent="yes"/>
    <xsl:template match="/">
        <xsl:variable name="var1_SwiftMessages" as="node()?" select="SwiftMessages"/>
        <xformResult xmlns="urn:...">
            <xsl:attribute name="xsi:schemaLocation" namespace="http://www.w3.org/2001/XMLSchema-instance" select="'urn:... OutputInterface/xformResult.xsd'"/>
            <xformResultRecord>
                <xformResultData>
                    <Document>
                        <!-- example of code that might be in here -->
                        <xsl:apply-templates select="$var1_SwiftMessages/Customer" />
                    </Document>
                </xformResultData>
            </xformResultRecord>
        </xformResult>
    </xsl:template>

    <xsl:template match="Customer">
        <Cstmr>
            <!-- contents of Cstmr element -->
        </Cstmr>
    </xsl:template>
Run Code Online (Sandbox Code Playgroud)

这里要理解的关键是应用于文字结果元素的命名空间绑定是在被视为纯XML文档时在样式表中的相关位置生效的那些.的xformResult,xformResultRecord,xformResultDataDocument元素都在urn:...命名空间,因为被声明为的默认xformResult样式表中的元素,但Cstmr在客户模板元素是不是在一个命名空间.相反,如果您将xmlns声明从上xformResult移到xsl:stylesheet:

<xsl:stylesheet version="2.0" xmlns="urn:..." xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:core="http://www.altova.com/MapForce/UDF/core" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions" exclude-result-prefixes="core xs fn">
    <xsl:template name="core:firstCharacter">
        ...
    </xsl:template>
    <xsl:template name="core:tokenize-by-length-internal">
        ...
    </xsl:template>
    <xsl:output method="xml" encoding="UTF-8" byte-order-mark="no" indent="yes"/>
    <xsl:template match="/">
        <xsl:variable name="var1_SwiftMessages" as="node()?" select="SwiftMessages"/>
        <xformResult>
            <xsl:attribute name="xsi:schemaLocation" namespace="http://www.w3.org/2001/XMLSchema-instance" select="'urn:... OutputInterface/xformResult.xsd'"/>
            <xformResultRecord>
                <xformResultData>
                    <Document>
                        <!-- example of code that might be in here -->
                        <xsl:apply-templates select="$var1_SwiftMessages/Customer" />
                    </Document>
                </xformResultData>
            </xformResultRecord>
        </xformResult>
    </xsl:template>

    <xsl:template match="Customer">
        <Cstmr>
            <!-- contents of Cstmr element -->
        </Cstmr>
    </xsl:template>
Run Code Online (Sandbox Code Playgroud)

然后,这将把所有未加前缀的文字结果元素放入urn:...命名空间,包括Cstmr.