首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >基于XSL的转换后删除空的xmlns元素

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

Stack Overflow用户
提问于 2013-12-16 15:30:37
回答 2查看 5.3K关注 0票数 2

最近,我一直在使用一个使用XSL修改输入数据格式的数据转换工具。我最近有了been having problems with the namespaces,现在我遇到了一个新的问题,这是由于解决了前面的问题。

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

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

XSLT片段

代码语言:javascript
复制
<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>

urn:...是对输出文件的规范的引用,而xformResult.xsd是输出文件的架构。

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

代码语言:javascript
复制
<?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>

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

EN

回答 2

Stack Overflow用户

发布于 2013-12-16 15:54:17

命名空间声明不是属性,尽管它们看起来是一样的。如果在输出中的元素上出现了xmlns="",则意味着在已经生效的默认名称空间存在的情况下,向树中添加了一个没有命名空间的元素。为了输出这样的结构,序列化程序必须用xmlns=""取消默认设置。

要解决这个问题,您需要首先在正确的命名空间中创建元素。例如,假设您的输入XML类似于

代码语言:javascript
复制
<example xmlns="http://example.com">
  <child1/>
</example>

您希望用child1替换为child2。以下内容如下:

代码语言:javascript
复制
<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>

会产生像你看到的结果

代码语言:javascript
复制
<example xmlns="http://example.com">
  <child2 xmlns=""/>
</example>

因为样式表在没有命名空间中创建child2元素。但是如果将xmlns="http://example.com"添加到样式表中

代码语言:javascript
复制
<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>

然后,它将产生正确的结果。

代码语言:javascript
复制
<example xmlns="http://example.com">
  <child2 />
</example>

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

代码语言:javascript
复制
  <xsl:template match="/*/*" xmlns="http://example.com">
    <child2/>
  </xsl:template>

编辑:引用您的具体示例:

代码语言:javascript
复制
<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>

这里需要理解的关键是,应用于文字结果元素的命名空间绑定是那些在样式表中的相关位置作为普通XML文档处理的名称空间绑定。xformResultxformResultRecordxformResultDataDocument元素位于urn:...命名空间中,因为这被声明为样式表中xformResult元素的缺省值,但客户模板中的Cstmr元素不在名称空间中。如果您将xmlns声明从xformResult向上移动到xsl:stylesheet

代码语言:javascript
复制
<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>

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

票数 6
EN

Stack Overflow用户

发布于 2013-12-16 15:51:06

您在转换(或输入数据)的其他地方肯定有问题。这是,而不是,而是序列化的问题。

以下两个例子有不同的含义。在第一个中,body在根元素上设置了xhtml命名空间,因为它是默认的。

代码语言:javascript
复制
<html xmlns="http://www.w3.org/1999/xhtml">
<body>
</body>
</html>

在第二个示例中,您将覆盖默认名称空间,并显式地声明body节点来自名称空间空字符串。它是一个与ih xhtml命名空间不同的对象。

代码语言:javascript
复制
<html xmlns="http://www.w3.org/1999/xhtml">
<body xmlns="">
</body>
</html>

编辑:

如果执行其他转换是一个选项,下面的XSLT将将父名称空间(实际上是最合适的祖先的名称空间)应用于具有空名称空间的元素:

代码语言:javascript
复制
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

    <xsl:template priority="2" match="*">
        <xsl:choose>
            <xsl:when test="namespace-uri()=''">
                <xsl:element name="{local-name()}" namespace="{namespace-uri(ancestor::*[namespace-uri()!=''][1])}">
                    <xsl:apply-templates select="@* | node()"/>
                </xsl:element>
            </xsl:when>
            <xsl:otherwise>
                <xsl:element name="{local-name()}" namespace="{namespace-uri()}">
                    <xsl:apply-templates select="@* | node()"/>
                </xsl:element>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>

    <xsl:template priority="1" match="@* | node()">
        <xsl:copy-of select="."/>
    </xsl:template>

</xsl:stylesheet>

Edit2:

下面是一个允许的模式,它将验证任何内容,您只需要根元素的名称和名称空间(模式的targetNamespace属性)。对于演示,我遵循了上面的html示例。

代码语言:javascript
复制
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema version="1.0"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    targetNamespace="http://www.w3.org/1999/xhtml"
    elementFormDefault="qualified">

  <xs:element name="html">
    <xs:complexType>
      <xs:sequence>
        <xs:any processContents="lax" minOccurs="0" maxOccurs="unbounded" />
      </xs:sequence>
    </xs:complexType>
  </xs:element>

</xs:schema>
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/20614560

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档