【问题标题】:Namespace is applied to child elements命名空间应用于子元素
【发布时间】:2017-02-02 16:41:03
【问题描述】:

我有以下输入(为简洁起见,不包括完整文件):

input.xml

<Request>
    <EFS>
        <child1>
            <!-- children -->
        </child1>
        <child2>

        </child2>
    <!-- more children etc-->
    </EFS>
</Request>

我想删除&lt;Request&gt; 元素,所以&lt;EFS&gt; 成为新的根元素,然后我想将命名空间添加到它。我的 XSL 如下(也缩短了):

我的样式表.xsl

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

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

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

<xsl:template match="EFS">
   <xsl:element name="EFS" xmlns="'http://www.EFS-standards.org/standards/PC_Surety/EFS1.6.12/xml/Intake'">
       <xsl:call-template name="createEFScontent"/>
       <xsl:apply-templates/>
    </xsl:element>
</xsl:template>

<xsl:template name="createEFScontent">
        <xsl:element name="AuditTotal">
            <xsl:element name="TransmissionID" />
            <xsl:element name="MessageQuantity" />
            <xsl:element name="TotalAmt">0.00</xsl:element>
        </xsl:element>
</xsl:template>

<!-- rest of stylesheet -->

所以&lt;Request&gt; 被删除,&lt;EFS&gt; 成为新的根。在此之后,我将命名空间应用于&lt;EFS&gt;,输出如下所示:

输出.xml

<EFS xmlns="'http://www.EFS-standards.org/standards/PC_Surety/EFS1.6.12/xml/Intake'">
   <AuditTotal xmlns="">
      <TransmissionID/>
      <MessageQuantity/>
      <TotalAmt>0.00</com.LibertyMutual_TotalAmt>
   </AuditTotal>
   <child1 xmlns="">
      //children
   </child1>
   <child2 xmlns="">
       <!-- children -->
   </child2>
   <!-- rest of output -->

我不确定出了什么问题。我希望输出看起来像现在在子 1 和 2 上没有 xmlns="" 的情况。我需要添加另一个模板来去除这些吗?我在列出的模板中犯了错误吗?

我正在使用 SaxonHE 9.7.0-8,这是在转换步骤中从 Camel 路由中调用的(如果这有什么不同的话)。另外值得注意的是,它仅将空白命名空间应用于子 1 和 2 元素。 EFS 没有其他子元素,但是 child1 和 child2 的子元素没有 xmlns=""

编辑:按照 Tim C 的回答,我已将 Identity 模板替换为他的并添加了模板:

<xsl:template match="@*|text()|comment()|processing-instruction()">
    <xsl:copy />
</xsl:template>

这会将命名空间应用于 EFS。当我添加如下模板时,命名空间要么在某些 elelements 上显示为空白,要么显示为完整的命名空间值:

    <xsl:template match="EFS/child1/AddRq/Policy">
    <xsl:copy>
        <xsl:element name="RDDCd">
            <xsl:call-template name="getRDDCd" />
        </xsl:element>
        <xsl:apply-templates select="node()"/>
    </xsl:copy>
</xsl:template>

运行时,Policy 将输出 xmlns="" 并且 RDDCd(连同 Policy 的现有子元素)将包含 xmlns=

xsl 中有很多这样的模板;我试图复制匹配元素的现有内容,并添加一个新内容,然后返回标识模板(我想,我对 xsl 不太好)。我做错了什么吗?我的大多数模板都与源中的元素匹配,复制内容并添加一个新的子元素(涵盖样式表中大约 70% 的模板)。如前所述,我一直在以上述方式创建这些模板,剩下的就是删除元素:

<template match="MSDCd" />

或更改元素/子元素的值。

【问题讨论】:

    标签: xml xslt


    【解决方案1】:

    如果您要创建新元素,例如 AuditTotal,那么您需要确保这些元素也是使用新命名空间创建的。你可以这样做..

    <xsl:element name="AuditTotal" namespace="http://www.EFS-standards.org/standards/PC_Surety/EFS1.6.12/xml/Intake">
        <xsl:element name="TransmissionID" />
        <xsl:element name="MessageQuantity" />
        <xsl:element name="TotalAmt">0.00</xsl:element>
    </xsl:element>
    

    ...但是在你的 XSLT 中定义一个默认命名空间会更容易

    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema" 
    xmlns="http://www.EFS-standards.org/standards/PC_Surety/EFS1.6.12/xml/Intake"
    version="2.0"> 
    

    此外,对于标识模板,您使用的是xsl:copy,但是这些会从源文档中复制元素,这些元素不在命名空间中,因此它们在输出中也没有命名空间。相反,您还需要在所需的命名空间中创建新元素。

    确实,如果您的 XML 中的所有元素都不在命名空间中,但您希望输出 XML 中的所有元素都在命名空间中,那么您不应该在 XSLT 中的任何地方使用xsl:copy。你应该用这个替换xsl:copy..

    <xsl:element name="{local-name()}">
    

    试试这个 XSLT:

    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema" 
    xmlns="http://www.EFS-standards.org/standards/PC_Surety/EFS1.6.12/xml/Intake"
    version="2.0"> 
    <xsl:output method="xml" indent="yes" version="1.0" encoding="UTF-8" omit-xml-declaration="yes"/>
    <xsl:strip-space elements="*" />
    
    <xsl:template match="*">
        <xsl:element name="{local-name()}">
            <xsl:copy-of select="@*" copy-namespaces="no" />
            <xsl:apply-templates select="@*|node()" />
        </xsl:element>
    </xsl:template>
    
    <xsl:template match="@*|text()|comment()|processing-instruction()">
        <xsl:copy />
    </xsl:template>
    
    <xsl:template match="/*">
        <xsl:apply-templates select="node()" />
    </xsl:template>
    
    <xsl:template match="EFS">
       <xsl:element name="EFS">
           <xsl:call-template name="createEFScontent"/>
           <xsl:apply-templates/>
        </xsl:element>
    </xsl:template>
    
    <xsl:template name="createEFScontent">
        <xsl:element name="AuditTotal">
            <xsl:element name="TransmissionID" />
            <xsl:element name="MessageQuantity" />
            <xsl:element name="TotalAmt">0.00</xsl:element>
        </xsl:element>
    </xsl:template>
    </xsl:stylesheet>
    

    【讨论】:

    • 所以这种工作,我将添加更多到输入/输出 xml,但基本上我在模板中匹配的任何其他元素现在要么有 xmlns="",要么是完整的xmlns 字符串
    • 实际上我已经缩小了添加命名空间的条件。在某些模板中,我匹配一个特定的元素,然后我调用 ,然后做任何需要做的事情,例如,然后是 。一旦我这样做了,我要么得到具有完整命名空间值的 xmlns,要么得到空白值。将更新问题
    • 在这种情况下你不应该使用&lt;xsl:copy&gt;。如果元素在源 XML 中没有命名空间,它将被复制到没有命名空间的输出 XML,从而显示 xmlns=''。你应该改用&lt;xsl:element name="{local-name()}"&gt;
    • 我已经更新了这个问题,提供了有关样式表意图的更多信息。我或多或少想匹配源中的元素,复制它们及其内容,并在大约 70% 的情况下添加一个新元素,然后,由于缺乏更好的表达方式,将控制权返回给标识模板,.我一直在使用问题末尾发布的格式;据我了解,xsl copy 会复制元素内容,但这是进行这种操作的错误方式吗?
    • 无命名空间中的元素与命名空间中的元素不同,即使实际名称相同。因此,您需要创建一个新元素,而不是复制现有元素,这就是我说使用 &lt;xsl:element name="{local-name()}"&gt; 的原因。
    【解决方案2】:

    您不能只为此使用标准身份模板。您需要模板来匹配每个不同的案例,然后复制没有命名空间的名称/内容。这样的事情应该可以工作,但请注意,在您的情况下,它可能不会为您提供空元素 (child2) 的预期行为。这为您要复制的每种节点类型提供了模板,并且默认情况下将所有内容放在您想要的命名空间中(样式表根中的xmlns):

    <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"  version="2.0"
    xmlns="http://www.EFS-standards.org/standards/PC_Surety/EFS1.6.12/xml/Intake"> 
        <xsl:output method="xml" indent="yes" version="1.0" encoding="UTF-8" omit-xml-declaration="yes"/>
        <xsl:strip-space elements="*" />
    
        <xsl:template match="*">
    
            <xsl:element name="{local-name()}">
                <xsl:apply-templates select="@*|node()" />
            </xsl:element>
    
        </xsl:template>
    
        <xsl:template match="@*">
            <xsl:attribute name="{local-name()}">
                <xsl:value-of select="." />
            </xsl:attribute>
        </xsl:template>
    
        <xsl:template match="text()|processing-instruction()|comment()">
            <xsl:copy-of select="." />
        </xsl:template>
    
        <xsl:template match="/*">
            <xsl:apply-templates select="." />
        </xsl:template>
    
        <xsl:template match="EFS">
            <xsl:element name="EFS">
                <xsl:call-template name="createEFScontent"/>
                <xsl:apply-templates/>
            </xsl:element>
        </xsl:template>
    
        <xsl:template name="createEFScontent">
            <xsl:element name="AuditTotal">
                <xsl:element name="TransmissionID" />
                <xsl:element name="MessageQuantity" />
                <xsl:element name="TotalAmt">0.00</xsl:element>
            </xsl:element>
        </xsl:template>
    
    </xsl:stylesheet>
    

    【讨论】:

    • 这是针对下游系统的,据我所知,元素必须在没有命名空间前缀的情况下进入。这是一个奇怪的要求,但只有新根必须有 xmlns 部分,其余的必须保持原样
    • 编辑了答案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-04
    • 1970-01-01
    • 2015-02-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多