XSLT 合并两个具有不同命名空间的文件

XSLT merging two files with different namespaces

这是我的主 HTML 文件,具有预定义的命名空间:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <title>some title</title>
    </head>
    <body>
        <p>some text</p>
    </body>
</html>

我还有一个这样定义的 XML 文件:

<?xml version="1.0" encoding="UTF-8"?>
<article dtd-version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:mml="http://www.w3.org/1998/Math/MathML">
    <front>
        <element>front text</element>
    </front>
    <back>
        <extra-list>
            <element>element text</element>
        </extra-list>
    </back>
</article>

这是想要的最终输出(来自 html 文件的头部,来自 xml 文件的额外列表):

<?xml version="1.0" encoding="UTF-8"?>
<xml>
  <head>
    <title>some title</title>
  </head>
  <back>
    <extra-list>
      <element>element text</element>
    </extra-list>
  </back>
</xml>

我正在尝试将这两个文件与下面的 XSLT 结合起来:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:transform
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:xlink="http://www.w3.org/1999/xlink"
  xpath-default-namespace="http://www.w3.org/1999/xhtml"
  version="2.0">
  
  <xsl:output method="xml" version="1.0" indent="yes"/>
  
  <xsl:template match="node()|@*">
    <xsl:copy>
      <xsl:apply-templates select="node()|@*"/>
    </xsl:copy>
  </xsl:template>
  
  <xsl:template match="html">
    <xml>
      <xsl:apply-templates/>
    </xml>
  </xsl:template>
  
  <xsl:template match="head">
    <head>
      <xsl:apply-templates/>
    </head>
  </xsl:template>
  
  <xsl:template match="body">
    <back>
      <xsl:copy-of select="document('doc.xml')"/>       
    </back>
  </xsl:template>
  
</xsl:transform>

我在 XSLT 中使用 xpath-default-namespace 所以我不必一直处理 HTML 的命名空间(原来的 master HTML 很大)我想如果可能,请保留此参数。这里我有两个问题:

1.) 如何摆脱所有 xmlns 输出声明?

2.) 使用此命令<xsl:copy-of select="document('doc.xml')"/> 只能复制整个xml 文件。如果我尝试只复制子元素 <xsl:copy-of select="document('doc.xml')/article/back"/>,那么我不会得到任何输出,因为内容不在同一个命名空间中。我该如何解决这个问题?

更新(完整的 XSLT 解决方案):

Based on Martin's answer below, this is fully working solution.

<?xml version="1.0" encoding="UTF-8"?>
<xsl:transform
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xpath-default-namespace="http://www.w3.org/1999/xhtml"
  version="2.0">
  
  <xsl:output method="xml" version="1.0" indent="yes"/>
  
  <!-- copy all elements and ignore namespace -->
  <xsl:template match="*">
    <xsl:element name="{local-name()}">
      <xsl:apply-templates select="@* | node()"/>
    </xsl:element>
  </xsl:template>
  
  <!-- copy all attributes and ignore namespace -->
  <xsl:template match="@*">
    <xsl:attribute name="{local-name()}">
      <xsl:value-of select="."/>
    </xsl:attribute>
  </xsl:template>
  
  <!-- copy all remaining nodes and ignore namespace -->
  <xsl:template match="comment() | text() | processing-instruction()">
    <xsl:copy/>
  </xsl:template>
  
  <xsl:template match="html">
    <xml>
      <xsl:apply-templates/>
    </xml>
  </xsl:template>
  
  <xsl:template match="head">
    <head>
      <xsl:apply-templates/>
    </head>
  </xsl:template>
  
  <xsl:template match="body">
    <xsl:copy-of xpath-default-namespace="" copy-namespaces="no" select="document('doc.xml')/article/back"/>    
  </xsl:template>
  
</xsl:transform>

我还添加了两个额外的模板来复制属性和一些其他节点。

您可以在需要时覆盖 xpath-default-namespace,例如<xsl:copy-of xpath-default-namespace="" select="document('doc.xml')/article/back"/>.

至于命名空间,有几个问题。您 运行 在 XHTML 名称空间中输入的部分通过身份转换,这始终保留了被复制的元素的名称空间。您将需要从身份转换更改为从元素中剥离命名空间的转换:

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

您在 XSLT 中创建的文字结果元素在您声明但不在 XSLT 代码中使用的范围内具有 XLink 命名空间。删除声明或在 xsl:stylesheetxsl:transform 元素上使用 exclude-result-prefixes="xlink"

您使用 document('doc.xml') 访问的其他输入也声明了未使用的名称空间,默认复制会保留它们,但由于它们仅在范围内但未使用,您可以使用 [=16= 删除它们]:<xsl:copy-of xpath-default-namespace="" select="document('doc.xml')/article/back" copy-namespaces="no"/>。或者,您还需要使用 xsl:element name="{local-name()}".

通过模板剥离命名空间推送这些元素