【问题标题】:XSL to transform only elements in a certain namespaceXSL 仅转换特定命名空间中的元素
【发布时间】:2012-09-24 17:23:35
【问题描述】:

我有一个结构有点像这样的 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.)(主要问题)根元素被复制而不是更改根元素的默认命名空间。所以基本上目录元素仍然在命名空间 format_old 中。

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

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

而不是从根元素中获取命名空间,而是将其保留为

<book>
  ...
</book>

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

【问题讨论】:

    标签: xml xslt xml-namespaces xalan


    【解决方案1】:

    我认为应该这样做:

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

    【讨论】:

      【解决方案2】:

      你已经接近了。您的默认模板正在挑选您没有其他模板的所有内容。

      您的第一个问题是他们选择了 orig:catalog 元素并将其原封不动地写出来,结果证明这不是您想要的。简单的修复:为它添加一个模板。

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

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

      • 1234563有关更多详细信息,请参阅this SO question
      • 在 SAX 或您喜欢的编辑器中编写一个简单的过滤器,让您自己完全控制命名空间的声明位置和方式。 (XSLT 的设计认为您应该非常担心命名空间声明,因此很难很好地控制它们。)

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

      不同的人使用这些不同的技术获得不同程度的成功;我自己,我发现最后一个特别有效,我只担心其他的当它失效时。

      【讨论】:

        猜你喜欢
        • 2020-03-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-05-20
        • 1970-01-01
        • 2014-03-12
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多