XSL输出没有前缀的XML而不使用默认名称空间?

XSL输出没有前缀的XML而不使用默认名称空间?,xml,xslt,xml-namespaces,Xml,Xslt,Xml Namespaces,我有一个XSL,我需要在其中生成以下内容的输出: <moo xmlns="http://api.example.com"> <foo>1358944586848</foo> <bar> <a>1</a> <b>2</b> <c>3</c> </bar> </moo> 但是我必须在我

我有一个XSL,我需要在其中生成以下内容的输出:

<moo xmlns="http://api.example.com">
    <foo>1358944586848</foo>
    <bar>
        <a>1</a>
        <b>2</b>
        <c>3</c>
    </bar>
</moo>
但是我必须在我创建的每个元素上显式地设置这个名称空间,否则它们将以XSL名称空间结束。那么,有没有一种干净的方法来创建具有特定名称空间(没有前缀)且不触及xsl文件的默认名称空间的元素呢


更新:

我想也许
名称空间别名
可以做点什么,但我不知道如何使用它。尝试了这一点,但似乎对输出没有任何影响:

<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 -->
subject.xsl


这种
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 -->
或者像这样:

<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 -->
<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 -->

我对混乱的感觉与您相同,特别是如果我有样式表,其中绝大多数元素都在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 -->

您可以做的一件事是在一个变量中捕获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>



这看起来不对。要让它工作,它应该是
。问题是输出结果带有
o
前缀,这正是我想要避免的。@Svish:哦,是的,你说得对-我想说些不同的话。谢谢你的提示。相应地更改了答案。这会起作用,但输出仍然会以
o:
前缀结束。我通常不关心这一点。任何使用该文件的XML解析器都应该以这样或那样的方式正确处理它。但你是对的,我曾经遇到过一个问题,其他人在一个可能不是XHTML的web应用程序中抛出了一些SVG输出,然后遇到了问题。是的,我的输出通常有前缀,但是在本例中,它将使用一个比较旧的第三方系统,这很困难:)直接将XML片段粘贴在其中的问题是,您必须在两个位置而不是一个位置定义元素的名称。可能看起来是个小问题,但我发现把它放在一个地方要容易得多。另外,由于您在这里使用的是默认名称空间,所以
都可以很好地工作。@Svish,将它也放在末尾实际上对我来说是一个加号:它提供了更好的可读性,因为我可以看到元素的结尾在哪里,而
xsl:element
的情况并非如此。您处理的片段越大,这一点就越重要。只有当我没有静态名称并且必须动态计算时,我才使用
xsl:element
。在这种情况下,我们必须使用一个非常烦人且速度缓慢的工具,在这种情况下,更正属性值要比更正两个元素名称快得多,这可能会让我有点生气。因为当我更改开始标记时,工具想要告诉我这里有未关闭/不匹配/错误的xml,并且告诉我这样做的速度非常慢:请看你的观点!您的解决方案仍然使用默认名称空间,这是我希望避免的。重新编辑:将不得不向每个模板元素添加xmlns?关于您的更新和
名称空间别名
-您的示例可能实现的唯一一件事是将
moo
写入
http://www.w3.org/1999/XSL/Transform
名称空间。我从未尝试过使用空前缀,我不确定这是否是
名称空间别名
的有效用法(未选中)。似乎您也可以使用
#default
作为
名称空间别名
属性的值。仍然没有达到我希望的效果…我会在几秒钟内添加一个编辑,它可能会达到你想要的效果。。。试试看,我不建议去掉“xsl:”前缀。最好使用好的代码格式。名称空间的唯一目的是消除歧义。在使用两个不同的词汇表时,隐藏前缀通常会导致混淆——这正是您的情况。通常,源XML文档可能具有诸如“输出”、“元素”、“属性”、“变量”等元素名称。在这种情况下,如果:xsl:如果去掉前缀,就很难区分哪个是源xml文档,哪个是XSLT样式表。可能会发生恼人且耗时的错误。@Svish,我非常尊重您的个人喜好。但是,如果这段代码不仅仅是为了您的眼睛,如果您保持“xsl:”前缀不变,那么其他人将更容易阅读。另一个重要因素是,某些XSLT IDE仅在使用前缀“xsl:”时才进行语法检查——即使使用了另一个前缀(如“XSLT:”),它们也会停止这样做。实际上,这种方法解决了这个问题。我的目标不是在XSL代码中避免前缀,而是在输出中避免前缀。对不起,如果不清楚的话。我会更新我的问题。@Svish非常感谢您接受我的回答。如果你想展示你的最终版本,请将其添加到你的问题文本中,而不是替换我文章的内容。我认为在答案中添加它更合适,所以我将其附加在那里,但不用担心。我看你已经把它搬走了:)
<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 -->
<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>