【问题标题】:XSL output XML with no prefix without using the default namespace?XSL 输出没有前缀的 XML 而不使用默认命名空间?
【发布时间】:2023-04-05 03:28:01
【问题描述】:

我有一个 XSL,我需要按照以下方式生成输出:

<moo xmlns="http://api.example.com">
    <foo>1358944586848</foo>
    <bar>
        <a>1</a>
        <b>2</b>
        <c>3</c>
    </bar>
</moo>

我可以这样做:

<xsl:stylesheet version="2.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns="http://api.example.com">

    <xsl:template match="/">
        <xsl:element name="moo">
            <!-- and so on -->

但是,我有点讨厌在我的 xsl 文件中使用 xsl 前缀,因为我觉得它很混乱。无论如何,使用 XPath 选择很容易,因为如果需要,您可以将 xpath-default-namespace 设置为您要转换的任何内容。但是据我所知,没有可用的element-default-namespace,那么我怎样才能以一种好的方式生成想要的输出呢?

我知道我可以做到:

<stylesheet version="2.0"
    xmlns="http://www.w3.org/1999/XSL/Transform">

    <template match="/">
        <element name="moo" namespace="http://api.example.com">
            <!-- and so on -->

但是我必须在我创建的每个元素上显式设置此命名空间,否则它们最终将使用 XSL 命名空间。那么有没有一种干净的方法来创建具有特定命名空间(不带前缀)的元素并且不触及 xsl 文件的默认命名空间?


更新:

想也许namespace-alias 可以做点什么,但不知道如何使用它。试过这个,但似乎对输出没有任何影响:

<stylesheet version="2.0"
    xmlns="http://www.w3.org/1999/XSL/Transform"
xmlns:out="http://api.example.com">

<namespace-alias stylesheet-prefix="out" result-prefix=""/>

    <template match="/">
        <element name="out:moo">
            <!-- and so on -->

namespace-alias 的事情可能没有按照我的想法做:p

我使用的最终解决方案,基于 JLRishe 的回答

remove-prefixes.xsl

<?xml version="1.0" encoding="UTF-8"?>
<stylesheet version="2.0" xmlns="http://www.w3.org/1999/XSL/Transform">
    <template match="/">
        <variable name="result">
            <next-match />
        </variable>
        <apply-templates select="$result" mode="remove-prefixes" />
    </template>

    <template match="*" priority="1" mode="remove-prefixes">
        <element name="{local-name()}" namespace="{namespace-uri()}">
            <apply-templates select="@* | node()" mode="remove-prefixes" />
        </element>
    </template>
    <template match="@*|node()" mode="remove-prefixes">
        <copy>
            <apply-templates select="@* | node()" mode="remove-prefixes" />
        </copy>
    </template>

</stylesheet>

subject.xsl

<!-- snip -->
<import href="remove-prefixes.xsl" />
<!-- snip -->

【问题讨论】:

  • 关于您的更新和namespace-alias - 您的示例可能实现的唯一事情是moo 被写为http://www.w3.org/1999/XSL/Transform 命名空间中。我从来没有尝试过使用空前缀,我不确定这是否真的是namespace-alias 的有效用法(尚未检查)。
  • 似乎您也可以使用#default 作为namespace-alias 属性的值。似乎仍然没有像我希望的那样做......
  • 我将在几秒钟内添加一个编辑,这可能会满足您的需求...试试看。
  • 我不建议丢失“xsl:”前缀。更好的是,使用良好的代码格式。命名空间的唯一目的是消除歧义。在使用两个不同的词汇表时,隐藏前缀通常会导致混淆——这正是你的情况。通常,源 XML 文档可能具有元素名称,例如“输出”、“元素”、“属性”、“变量”。在这种情况下,如果去掉 :xsl:" 前缀,就很难区分哪个是源 xml 文档,哪个是 XSLT 样式表。可能会出现烦人且耗时的错误。
  • @Svish,我非常尊重您的个人喜好。但是,如果此代码不仅是为了您的眼睛,那么如果您保留“xsl:”前缀不变,其他人都会更容易阅读。另一个重要因素是,某些 XSLT IDE 仅在使用前缀“xsl:”时才进行语法高亮——即使使用了另一个前缀(例如“xslt:”),它们也会停止这样做。

标签: xml xslt xml-namespaces


【解决方案1】:

您可以做的一件事是在一个变量中捕获 XSL 的整个结果,然后在最后将其前缀清空:

<stylesheet version="2.0" xmlns="http://www.w3.org/1999/XSL/Transform"
                          xmlns:p="http://api.example.com">
  <output method="xml" indent="yes"/>

  <template match="/">
    <variable name="result">
      <p:moo>
        <apply-templates />
      </p:moo>
    </variable>
    <apply-templates select="$result" mode="removePrefix" />
  </template>

  <template match="root">
    <p:something hello="hi">
      <element name="p:somethingelse" />
    </p:something>
  </template>

  <template match="p:*" mode="removePrefix">
    <element name="{local-name()}" namespace="{namespace-uri()}">
      <apply-templates select="@* | node()" mode="removePrefix" />
    </element>
  </template>

  <template match="@* | node()" mode="removePrefix">
    <copy>
      <apply-templates select="@* | node()" />
    </copy>
  </template>
</stylesheet>

在此输入上运行时:

<root>
  <top />
</root>

它产生:

<moo xmlns="http://api.example.com">
  <something hello="hi">
    <somethingelse />
  </something>
</moo>

【讨论】:

  • 其实这种解决方法。我的目标不是在 XSL 代码中避免前缀,而是在输出中。抱歉,如果不清楚。我会更新我的问题。
  • @Svish 非常感谢您接受我的回答。如果您想展示您的最终版本,请将其添加到您的问题文本中,而不是替换我帖子的内容。
  • 认为将它包含在答案中会更合适,所以我将它附加在那里,但不用担心。我看到你已经把它搬走了:)
【解决方案2】:

xmlns:xsl-方法确实是“标准”的一天,我想 XSL 的设计者已经想到了这一点。

请记住,您可以将 XML 片段直接混合到 XSL 中。从这个角度来看,您使用 xsl:element 的方法可以说比您尝试使用“元素默认命名空间”消除的方法增加了更多的噪音和混乱。

所以,我会这样做:

<xsl:stylesheet version="2.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns="http://api.example.com">

    <xsl:template match="/">
        <moo>
            <!-- and so on -->

编辑:

namespace-alias 的以下内容可能有效:

<xsl:stylesheet version="2.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns="http://api.example.com">

    <namespace-alias stylesheet-prefix="xsl" result-prefix="#default"/>

    <template match="/" xmlns="http://www.w3.org/1999/XSL/Transform">
        <element name="moo">
            <!-- etc -->

或者像这样:

<stylesheet version="2.0"
    exclude-result-prefixes="api" 
    xmlns="http://www.w3.org/1999/XSL/Transform"
    xmlns:api="http://api.example.com">

    <namespace-alias stylesheet-prefix="#default" result-prefix="api"/>

    <template match="/">
        <element name="moo">
            <!-- etc -->

【讨论】:

  • 直接在其中粘贴 XML 片段的问题是您必须在两个位置而不是一个位置定义元素的名称。可能看起来像一个小问题,但我发现将它保存在一个地方要容易得多。此外,由于您在这里使用的是默认命名空间,&lt;moo&gt;&lt;xsl:element name="moo"&gt; 都可以正常工作。
  • @Svish,把它放在最后对我来说实际上是一个加分项:它提供了更好的可读性,因为我可以看到元素在哪里结束,xsl:element 不是这种情况。您正在处理的片段越大,这一点就越重要。仅当我没有静态名称并且必须即时计算它时,我才使用 xsl:element
  • 好吧,在这种情况下,我们必须使用一个非常烦人且速度很慢的工具,因为它比两个元素名称更正属性值要快得多。因为当我更改开始标签时,该工具想告诉我这里有未关闭/不匹配/错误的 xml,而且告诉我的速度很慢:p
  • 看你的意思!您的解决方案仍然使用我希望避免的默认命名空间。
  • 重新编辑:然后必须将 xmlns 添加到每个模板元素?
【解决方案3】:

我对混乱的感觉和你一样,特别是如果我的样式表绝大多数元素都在 XSL 命名空间中,而不是在目标命名空间中。解决方案很简单:给输出元素一个前缀而不是 XSL 元素:

<stylesheet version="2.0"
    xmlns="http://www.w3.org/1999/XSL/Transform"
    xmlns:o="http://api.example.com">

    <template match="/">
        <o:moo>
            <!-- and so on -->

【讨论】:

  • 这看起来不对。要让它工作,它应该是&lt;element name="o:moo"&gt;。那么问题是输出以o 前缀结尾,这是我想要避免的。
  • @Svish:哦,是的,你是对的——我想说点不同的。感谢您的提示。相应地更改了答案。
  • 这可行,但输出仍会以o: 前缀结尾。
  • 我通常不关心这个。任何使用该文件的 XML 解析器都应该以一种或另一种方式正确处理它。但你是对的,我曾经遇到过问题,其他人在可能不是 XHTML 的 Web 应用程序中抛出一些 SVG 输出并遇到问题。
  • 是的,我的输出通常有前缀,但在这种情况下,它会用到一个相当老的 3rd-party 系统,它很困难:)
猜你喜欢
  • 1970-01-01
  • 2013-02-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多