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:stylesheet
或 xsl: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()}"
.
通过模板剥离命名空间推送这些元素
这是我的主 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:stylesheet
或 xsl: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()}"
.