【问题标题】:Default namespace is not transforming correctly默认命名空间未正确转换
【发布时间】:2013-03-29 05:48:33
【问题描述】:

我想为元素添加默认名称空间(转换时)。我使用 xslt 进行这种转换。请找到下面的代码sn-p。

<xsl:variable name="ns" select="'http://ABC.org/Standards/SChool/2'" />

<xsl:element name="School" namespace="{$ns}">
     <xsl:attribute name="Version">2.13.92</xsl:attribute>    
     <xsl:apply-templates select="ltc:UserAuthRequest" />
</xsl:element>

<xsl:template match="ltc:UserAuthRequest">
     <xsl:element name="{local-name()}">
</xsl:template>

转换后我得到了下面的 xml 输出。

<School xmlns="http://ABC.org/Standards/SChool/2" Version="2.13.92">
     <UserAuthRequest xmlns=""></UserAuthRequest>
</School>

这里的问题是默认命名空间也是在子节点中创建的。

谁能解释一下为什么命名空间是在子元素中创建的,即使我没有为此定义任何命名空间,以及如何避免这个问题?

输入 XML

<?xml version="1.0" encoding="UTF-8"?>
<School>

    <UserAuth>
        <UserName>K.Senthuran</UserName>
        <Password>Javaworld</Password>
    </UserAuth>

</School>

转换逻辑

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

    <xsl:template match="/School">

        <xsl:variable name="ns">www.school.com/myLife</xsl:variable>
        <xsl:element name="School" namespace="{$ns}">
            <xsl:apply-templates select="UserAuth" />
        </xsl:element>
    </xsl:template>

    <xsl:template match="UserAuth">
        <xsl:element name="UserAuth">
            <xsl:attribute name="id">sdmnsdnk</xsl:attribute>

            <xsl:apply-templates select="UserName" />
            <xsl:apply-templates select="Password" />
        </xsl:element>
    </xsl:template>

    <xsl:template match="UserName">
        <xsl:element name="{local-name()}">
            <xsl:attribute name="userIDREF">dmsdmsl</xsl:attribute>

            <xsl:value-of select="." />
        </xsl:element>
    </xsl:template>

    <xsl:template match="Password">

        <xsl:element name="{local-name()}">
            <xsl:attribute name="uniqueIDREF">asakjhs</xsl:attribute>

            <xsl:value-of select="." />
        </xsl:element>
    </xsl:template>

    <xsl:template match="@*">
        <xsl:attribute name="{name()}"><xsl:value-of select="." /></xsl:attribute>
    </xsl:template>

</xsl:stylesheet>

电流输出

<?xml version="1.0" encoding="UTF-8"?>
<School xmlns="www.school.com/myLife">
    <UserAuth xmlns="" id="sdmnsdnk">
        <UserName userIDREF="dmsdmsl">K.Senthuran</UserName>
        <Password uniqueIDREF="asakjhs">Javaworld</Password>
    </UserAuth>
</School>

预期输出

<?xml version="1.0" encoding="UTF-8"?>
<School xmlns="www.school.com/myLife">
    <UserAuth id="sdmnsdnk">
        <UserName userIDREF="dmsdmsl">K.Senthuran</UserName>
        <Password uniqueIDREF="asakjhs">Javaworld</Password>
    </UserAuth>
</School>

【问题讨论】:

  • 请提供实际的 XML 文档和所需的转换结果。

标签: xml xslt namespaces xslt-2.0


【解决方案1】:

问题在于,当您创建 UserAuthRequest 时,您并没有给它一个命名空间

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

因此,XSLT 将生成一个没有命名空间的元素,因此是 xmlns=""。假设您的 ns 变量在范围内是全局的,只需以与 School 元素相同的方式创建元素

<xsl:element name="{local-name()}" namespace="{$ns}" />

实际上,如果要匹配特定元素,则此处不需要 local-name。这也行

<xsl:element name="UserAuthRequest" namespace="{$ns}" />

【讨论】:

  • 感谢蒂姆的回答。应用您的建议后,我仍然面临同样的问题。我想你误解了我的问题。我的子元素中没有任何命名空间。我的意思是元素 UserAuthRequest 或其任何子元素不应该有任何命名空间。
【解决方案2】:

这里是如何做到这一点:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:variable name="vNs" select="'some:NS'"/>

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

 <xsl:template match="@*">
  <xsl:attribute name="{name()}"><xsl:value-of select="."/></xsl:attribute>
 </xsl:template>
</xsl:stylesheet>

当此转换应用于以下 XML 文档时:

<School Version="2.13.92">
     <UserAuthRequest></UserAuthRequest>
</School>

产生了想要的正确结果:

<School xmlns="some:NS" Version="2.13.92">
   <UserAuthRequest/>
</School>

更新:

OP 澄清了他的问题。现在,一个额外的要求是为某些元素添加新属性:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:variable name="vNs" select="'some:NS'"/>

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

 <xsl:template match="@*">
  <xsl:attribute name="{name()}"><xsl:value-of select="."/></xsl:attribute>
 </xsl:template>

 <xsl:template match="UserAuth">
  <xsl:element name="{name()}" namespace="{$vNs}">
   <xsl:attribute name="id">sdmnsdnk</xsl:attribute>
   <xsl:apply-templates/>
  </xsl:element>
 </xsl:template>

 <xsl:template match="UserName">
  <xsl:element name="{name()}" namespace="{$vNs}">
   <xsl:attribute name="userIDREF">dmsdmsl</xsl:attribute>
   <xsl:apply-templates/>
  </xsl:element>
 </xsl:template>
 <xsl:template match="Password">
  <xsl:element name="{name()}" namespace="{$vNs}">
   <xsl:attribute name="uniqueIDREF">asakjhs</xsl:attribute>
   <xsl:apply-templates/>
  </xsl:element>
 </xsl:template>
</xsl:stylesheet>

当此转换应用于提供的 XML 文档时:

<School>
    <UserAuth>
        <UserName>K.Senthuran</UserName>
        <Password>Javaworld</Password>
    </UserAuth>
</School>

产生了想要的正确结果:

<School xmlns="some:NS">
   <UserAuth id="sdmnsdnk">
      <UserName userIDREF="dmsdmsl">K.Senthuran</UserName>
      <Password uniqueIDREF="asakjhs">Javaworld</Password>
   </UserAuth>
</School>

【讨论】:

  • 感谢 Dimitre 的回答。根据您的方法,它按预期工作。但我正在以不同的方式进行改造。我添加了一些属性和其他元素。那时它不工作。请给我建议。
  • 我在这里有一个小小的说明。为什么即使您为子元素创建了命名空间,命名空间 ns 也没有申请其他子元素?
  • @K.Senthuran,这是“视错觉”,所有元素都在同一个默认命名空间中。这与实际显示顶部元素的每个后代的(默认)命名空间的表示等效(但更具可读性)。根据 XPath 数据模型和 W3C 命名空间规范,所有后代元素节点“继承”其父(以及祖先)的所有命名空间节点。与所有其他命名空间一样,默认命名空间会传播到所有后代。只能通过显式取消声明或声明另一个默认命名空间来更改和抑制它。
  • 感谢您的解释
猜你喜欢
  • 2015-04-13
  • 1970-01-01
  • 1970-01-01
  • 2018-12-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-12-26
  • 2014-04-16
相关资源
最近更新 更多