命名空间错误: 关键字上的命名空间前缀bd未定义

3
我有一个巨大的XML文件,想将其拆分成单个的XML文档;每个单独的XML文件都应该在适用的位置有一个显式的命名空间声明,如下面“期望的输出”部分所示。然而,我一直收到错误“namespace error: Namespace prefix bd on keyword is not defined”。
我的问题是,我如何明确告诉我的XSLT处理器在结果输出中放置命名空间声明?我已经查阅了几个在线教程,但我无法完全弄清楚如何解决这个问题。
部分XSLT片段
...
...
<xsl:template match="chapter">
  <bd:chapter>
    <xsl:apply-templates select="name" />
    <xsl:apply-templates select="page" />
  </bd:chapter>
</xsl:template>

<xsl:template match="name">
  <bd:name>
    <xsl:value-of select="." />
  </bd:name>
</xsl:template>
...
...

期望的输出

<?xml version="1.0" encoding="utf-8" ?>
<books>
<bd:book xmlns:bd="http://www.bd.org.za/db" xmlns:cd="http://www.bd.org.za/cd">
    <bd:name>book01</bd:name>
    <bd:chapter>
      <cd:name>chapter01<cd:name>
      <bd:page>
    <cd:title></cd:title>
    <pd:description></pd:description>
      </bd:page>
    </bd:chapter>
</bd:book>
...
...
...
</books>

更新 #1

<?xml version="1.0" encoding="utf-8" ?>
<books>
<book>
    <name>book01</name>
    <chapter>
      <name>chapter01<name>
      <page>
    <title></title>
    <description></description>
      </page>
    </chapter>
</book>
...
...
...
</books>

更新 #2

@polishchuk 更新2的结果如下

<?xml version="1.0"?>
<root xmlns:pd="namespace2">
  <pd:Book xmlns:pd="http://namespace1.org/">
    <pd_1:Name xmlns:pd="namespace2" xmlns:pd_1="http://namespace1.org/">A</pd_1:Name>
    <pd:Description xmlns:pd="namespace2">A1</pd:Description>
  </pd:Book>
  <pd:Book xmlns:pd="http://namespace1.org/">
    <pd_1:Name xmlns:pd="namespace2" xmlns:pd_1="http://namespace1.org/">B</pd_1:Name>
    <pd:Description xmlns:pd="namespace2">B1</pd:Description>
  </pd:Book>
</root>

我希望命名空间只出现在书籍节点内。请参见下面的示例:
<?xml version="1.0"?>
<root>
  <pd:Book xmlns:pd="http://namespace1.org/">
    <pd:Name >A</pd:Name>
    <pd:Description>A1</pd:Description>
  </pd:Book>
  <pd:Book xmlns:pd="http://namespace1.org/">
    <pd:Name>B</pd_1:Name>
    <pd:Description>B1</pd:Description>
  </pd:Book>
</root>

@polishchuk:感谢您的回复。输入的XML链接到太多节点...不过,现在您可以假设我们正在处理上面的更新#1中的代码。我只需要指针来明确包含命名空间到元素中的方法。 - lightonphiri
XML 引擎在名称空间定义的位置上没有区别。您可以在根节点 <root xmlns:pd="namespace2"> 或者书籍节点 <pd:Book xmlns:pd="namespace2"> 中定义名称空间,对于 XML 解析器来说这两者是相等的。 - Kirill Polishchuk
1个回答

2
假设你有以下XML文档:
<root>
  <book>
    <name>A</name>
    <description>A1</description>
  </book>
  <book>
    <name>B</name>
    <description>B1</description>
  </book>
</root>

期望的XML(带命名空间):

<root xmlns:bd="namespace1" xmlns:pd="namespace2">
  <bd:Book>
    <bd:Name>A</bd:Name>
    <pd:Description>A1</pd:Description>
  </bd:Book>
  <bd:Book>
    <bd:Name>B</bd:Name>
    <pd:Description>B1</pd:Description>
  </bd:Book>
</root>

适当的XSLT:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:bd="namespace1"
                xmlns:pd="namespace2"
                >
  <xsl:output method="xml" indent="yes"/>

  <xsl:template match="/">
    <root>
      <xsl:apply-templates/>
    </root>
  </xsl:template>

  <xsl:template match="book">
    <bd:Book>
      <xsl:apply-templates />
    </bd:Book>
  </xsl:template>

  <xsl:template match="name">
    <bd:Name>
      <xsl:value-of select="."/>
    </bd:Name>
  </xsl:template>

  <xsl:template match="description">
    <pd:Description>
      <xsl:value-of select="."/>
    </pd:Description>
  </xsl:template>

</xsl:stylesheet>

你只需在XSLT中添加命名空间,然后使用命名空间前缀创建节点即可。
更新1:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:pd="namespace2"
                >
  <xsl:output method="xml" indent="yes"/>

  <xsl:template match="/">
    <root>
      <xsl:apply-templates/>
    </root>
  </xsl:template>

  <xsl:template match="book">
    <bd:Book xmlns:bd="namespace1">
      <xsl:apply-templates />
    </bd:Book>
  </xsl:template>

  <xsl:template match="name">
    <bd:Name xmlns:bd="namespace1">
      <xsl:value-of select="."/>
    </bd:Name>
  </xsl:template>

  <xsl:template match="description">
    <pd:Description>
      <xsl:value-of select="."/>
    </pd:Description>
  </xsl:template>

</xsl:stylesheet>

更新2:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:pd="namespace2"
                >
  <xsl:output method="xml" indent="yes"/>

  <xsl:template match="/">
    <root>
      <xsl:apply-templates/>
    </root>
  </xsl:template>

  <xsl:template match="book">
    <Book xmlns="namespace1">
      <xsl:apply-templates />
    </Book>
  </xsl:template>

  <xsl:template match="name">
    <Name xmlns="namespace1">
      <xsl:value-of select="."/>
    </Name>
  </xsl:template>

  <xsl:template match="description">
    <pd:Description>
      <xsl:value-of select="."/>
    </pd:Description>
  </xsl:template>

</xsl:stylesheet>

更新 3: 这个 XSLT:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" indent="yes"/>

  <xsl:template match="/">
    <root>
      <xsl:apply-templates/>
    </root>
  </xsl:template>

  <xsl:template match="book">
    <pd:Book xmlns:pd="namespace2">
      <xsl:apply-templates />
    </pd:Book>
  </xsl:template>

  <xsl:template match="name">
    <pd:Name  xmlns:pd="namespace2">
      <xsl:value-of select="."/>
    </pd:Name>
  </xsl:template>

  <xsl:template match="description">
    <pd:Description  xmlns:pd="namespace2">
      <xsl:value-of select="."/>
    </pd:Description>
  </xsl:template>

</xsl:stylesheet>

输出XML(就像您在更新2中使用的MSXML 6.0),但对于无论名称空间定义在哪里的XML引擎:

<root>
  <pd:Book xmlns:pd="namespace2">
    <pd:Name>A</pd:Name>
    <pd:Description>A1</pd:Description>
  </pd:Book>
  <pd:Book xmlns:pd="namespace2">
    <pd:Name>B</pd:Name>
    <pd:Description>B1</pd:Description>
  </pd:Book>
</root>

谢谢您的回复;我实际上已经尝试过了。然而,我想要的是命名空间出现在内部节点之一——比如说这种情况下的 Book 元素,而不是根节点。我该如何明确地告诉 XSLT 呢?您的解决方案默认将命名空间声明放在根节点中。请记住,我将有多个 XML 文件,每个文件都应该定义相同的命名空间声明。 - lightonphiri
谢谢。我应该将相同的前缀指向两个不同的命名空间,有特定的原因吗?我需要理解这一点,以便正确地复制解决方案。xmlns:pd="namespace2" xmlns:bd="namespace1" - lightonphiri
@phiri,您可以省略前缀。只需写<Book xmlns="namespace1">即可。 - Kirill Polishchuk
@phiri,嗯...你能提供抽象的输入XML和期望的输出XML吗?这样我就可以理解你的需求了...? - Kirill Polishchuk
现在显式嵌入命名空间已经可以正常工作了。非常感谢! - lightonphiri
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接