XSL只转换某个命名空间中的元素

时间:2012-09-24 17:23:35

标签: xml xslt xml-namespaces xalan

我有一个xml文档,其结构有点像这样: -

<catalog xmlns="format_old" xmlns:final="format_new">
  <final:book>
    <final:title>blah</final:title>
    <final:author>more blah</final:author>
  </final:book>
  <book>
    <description title="blah2"/>
    <writer name="more blah2"/>
  </book>
</catalog>

显然,这是问题的简化版本。我想要做的是将其转换为: -

<catalog xmlns="format_new">
  <book>
    <title>blah</title>
    <author>more blah</author>
  </book>
  <book>
    <title>blah2</title>
    <author>more blah2</author>
  </book>
</catalog>

我现在拥有的样式表是这样的: -

<xsl:stylesheet version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:orig="format_old"
  xmlns="format_new"/>

<xsl:template match="@*|node()">
  <xsl:copy>
    <xsl:apply-templates select="@*|node()" />
  </xsl:copy>
</xsl:template>

<xsl:template match="//orig:book">
  <xsl:element name="title">
    <xsl:value-of select="./orig:description/@title" />
  </xsl:element>
  <xsl:element name="author">
    <xsl:value-of select="./orig:writer/@name" />
  </xsl:element>
</xsl:template>

</xsl:stylesheet>

这给了我一个输出: -

<catalog xmlns="format_old">
  <book xmlns="format_new">
    <title>blah</title>
    <author>more blah</author>
  </book>
  <book xmlns:orig="format_old" xmlns="format_new">
    <title>blah2</title>
    </author>more blah2</author>
  </book>
</catalog>

此样式表存在两个问题: -

1。)(主要问题)根元素被复制而不是更改根元素的默认命名空间。所以基本上,catalog元素仍然在命名空格format_old中。

2。)(小问题)这会将元素转换为: -

<book xmlns:orig="format_old" xmlns="format_new">
  ...
</book>

而不是从根元素中获取命名空间,因为它保持为

<book>
  ...
</book>

我在这里缺少什么?我正在使用Xalan-C。

2 个答案:

答案 0 :(得分:2)

我认为以下情况应该:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
    xmlns="format_new"
    xmlns:ns1="format_old"
    exclude-result-prefixes="ns1"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:template match="@* | text() | comment() | processing-instruction()">
  <xsl:copy/>
</xsl:template>

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

<xsl:template match="ns1:book/ns1:description[@title]">
  <title>
    <xsl:value-of select="@title"/>
  </title>
</xsl:template>

<xsl:template match="ns1:book/ns1:writer[@name]">
  <author>
    <xsl:value-of select="@name"/>
  </author>
</xsl:template>

</xsl:stylesheet>

Saxon 6.5.5将您的输入转换为

<?xml version="1.0" encoding="utf-8"?><catalog xmlns="format_new">
  <book>
    <title>blah</title>
    <author>more blah</author>
  </book>
  <book>
    <title>blah2</title>
    <author>more blah2</author>
  </book>
</catalog>

答案 1 :(得分:1)

你很亲密。您的默认模板正在拾取您没有其他模板的所有模板。

你的第一个问题是他们正在拿起orig:catalog元素并将其写成未更改,结果证明不是你想要的。简单修复:为其添加模板。

您的第二个问题是管理输出中的命名空间声明。在这里,有几种技巧可能会有所帮助:

  • 仔细阅读规范或您喜欢的XSLT参考中的xsl:exclude-result-prefixes文档;用它来告诉你的处理器你不需要为旧命名空间提供命名空间声明。

  • 如果要利用文字结果元素的输出始终携带样式表中LRE上找到的所有inscope名称空间前缀这一事实,请使用xsl:element构造函数而不是文字结果元素。有关详细信息,请参阅this SO question

  • 在SAX或您喜欢的编辑器中编写一个简单的过滤器,让您自己完全控制声明命名空间的位置以及方式。 (XSLT的设计认为你应该过多地担心名称空间声明,结果很难很好地控制它们。)

  • 如果您的输出具有一些无关的命名空间声明,请训练自己不要太在意,并且只要所有内容都正确绑定,就要写下游消费者做正确的事情,这样他们就不会被无关的命名空间声明所困扰。

不同的人使用这些不同的技术有不同程度的成功;我自己,我觉得最后一个特别有效,而且只有当它打破了我时才会担心其他的。