【问题标题】:Correct way of writing xsl:value-of in XSLT在 XSLT 中编写 xsl:value-of 的正确方法
【发布时间】:2012-06-01 06:06:17
【问题描述】:

我正在尝试编写 XSLT 来将我的 XML 从一种格式转换为另一种格式。当我将我的.xslt 文件应用到 VS 2010 中的 XML 文件时,输出 XML 结构的创建没有任何问题。但它没有填写处理xsl:value-of所期望的数据。

当我使用 XMLSpy 并计算 XPath 表达式时,它会为以下 XSLT 中的表达式显示 no result。但是当我在 XPath 表达式的末尾使用 node() 函数时,它会显示值!

  1. 编写 XPath 的正确方法是什么?
  2. 是否真的需要node() 和text() 之类的函数来读取元素内容(当它没有子元素时)?如果不是,为什么 XmlSpy 在没有这些功能的情况下也不给出结果?
  3. 有时(当我将模板匹配值从“/”更改为“ServiceMessage”时)在调试 XSLT 时,VS 2010 会进入内置模板规则。为什么会这样?如何摆脱 VS 2010 中的内置模板?

我一开始就关注w3school tutorial。我是 XSLT 的新手。

这是我想要转换为其他 XML 格式的 XML。

<ServiceMessage xmlns="http://requestservice/requests" xmlns:req="http://requestservice/requests/xmlstds">

<TypeOfReq> General </TypeOfReq>
<Details>
   <Id> 123456789 </Id>
   <SenderDetails>
        <Sender id="345"></Sender>
   </SenderDetails>
</Details>

</ServiceMessage>

这是我的 XSLT

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >
  <xsl:output method="xml" indent="yes"/>
  <xsl:template match="/">
    <request>
      <requestType>
        <xsl:value-of select="ServiceMessage/TypeOfReq" />
      </requestType>
      <Id>
        <xsl:value-of select="ServiceMessage/Details/Id"/>
      </Id>
      <senderId>
        <xsl:value-of select="ServiceMessage/Details/SenderDetails/Sender/@id"/>
      </senderId>
    </request>

  </xsl:template>



</xsl:stylesheet>

【问题讨论】:

  • 谢谢@Filburt。更正了错字。

标签: xml visual-studio-2010 xslt xpath


【解决方案1】:

从语法的角度来看,您已经正确地编写了 xpath。您实际遇到的问题实际上与名称空间有关。在您的 XML 中,您指定了默认命名空间

<ServiceMessage xmlns="http://requestservice/requests">

这意味着所有子元素,除非另有说明,都属于该命名空间。但是,在您的 XSLT 中,根本没有对此命名空间的引用,因此 XSLT 正在寻找没有指定命名空间的元素。这不是您的 XML 的情况。

对于 XSLT 1.0,您需要声明命名空间,如下所示:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:s="http://requestservice/requests"> 

然后您将明确说明它用于匹配元素的位置

<xsl:value-of select="s:ServiceMessage/s:TypeOfReq" />

这是完整的 XSLT

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:s="http://requestservice/requests">
   <xsl:output method="xml" indent="yes"/>
   <xsl:template match="/">
      <request>
         <requestType>
            <xsl:value-of select="s:ServiceMessage/s:TypeOfReq"/>
         </requestType>
         <Id>
            <xsl:value-of select="s:ServiceMessage/s:Details/s:Id"/>
         </Id>
         <senderId>
            <xsl:value-of select="s:ServiceMessage/s:Details/s:SenderDetails/s:Sender/@id"/>
         </senderId>
      </request>
   </xsl:template>
</xsl:stylesheet>

当应用于您的 XML 时,将输出以下内容

<request xmlns:s="http://requestservice/requests">
   <requestType> General </requestType>
   <Id> 123456789 </Id>
   <senderId>345</senderId>
</request>

请注意,这里选择的字母“s”纯属随意,它可以是任何东西。

【讨论】:

  • 太棒了!有效。我会接受它作为答案。但是您知道吗,为什么 XmlSpy 不提供没有 node() 或 text() 函数的结果?为什么它会正确评估 Xpath 表达式(在这种情况下我使用 node() )而没有在表达式中指定命名空间?
  • node() 将匹配元素、文本、cmets 和处理指令,而 text() 将仅匹配 text()。您通常不会将 text() 与 xsl:value-of 一起使用,因为此函数无论如何都会返回节点的文本。请注意(在 XSLT1.0 中)如果您执行 xsl:value-of 并且您的 xpath 表达式匹配多个节点,它只会返回它匹配的第一个节点的文本。
  • 接受这个作为答案,因为它已经准确地发现了问题并提供了解决方案。 @Filburt 回答了有关 VS 内置模板的其他问题。
【解决方案2】:

回答您的第三个问题“我怎样才能摆脱内置模板?”

如果您没有为 xml 中出现的元素指定模板,则在您的情况下,VS 将应用 身份模板,这会将源元素复制到您的输出中。

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

详情请见Microsoft's explanation on built in templates。

(atm 我不知道是否可以关闭它,因为我这里只有 VS Express,它不提供 Xslt 调试)

作为一般规则,您应该始终为要处理的所有元素指定模板,因此您的基本 xslt 将始终以

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:s="http://requestservice/requests">

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

</xsl:stylesheet>

接下来,根据您的情况,为根元素 ServiceMessage

添加一个模板
<xsl:template match="s:ServiceMessage">
    <!-- usually apply-templates, in your case create new output element(s) -->
<xsl:template>

【讨论】:

  • 谢谢@Filburt。它帮助我理解了我在 VS 2010 中调试时遇到的问题。
  • >> 如果您没有为 xml 中出现的元素指定模板,VS 将应用身份模板,该模板只会将源元素复制到您的输出中。
  • @torazaburo 如果您知道得更好,请告诉我们 - 否则我的答案包含Microsofts own definition的(缩短和简化)版本
  • 默认规则不复制源元素。它仅在其子级上执行&lt;xsl:apply-templates&gt;。如果不是这种情况,我们就没有理由在解决诸如此类问题的解决方案中经常看到复制样板(“复制 XML,但在途中做这个小转换......”)。默认规则唯一复制到输出的是文本节点。您引用的 MS 页面没有说默认规则复制节点,它说它处理它们。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-06-25
  • 1970-01-01
  • 2016-09-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多