基本的XML / XSLT转换:搜索&更换

时间:2009-09-30 23:15:37

标签: xml xslt

我是XML和XSLT的新手,并花了一些时间在一个非常简单的搜索和替换案例上。我似乎无法使语法正确。

本练习的总体目标是将元素'NewCustomer'中的'Y'和'N'的值分别替换为'true'或'false'。

这是我的样本数据。

<?xml version="1.0"?>
<CustomerList>
  <Customer>
    <CustomerID>1111</CustomerID>
    <CompanyName>Sean Chai</CompanyName>
    <City>New York</City>
    <NewCustomer>N</NewCustomer>
    </Customer>
  <Customer>
    <CustomerID>1112</CustomerID>
    <CompanyName>Tom Johnston</CompanyName>
    <City>Los Angeles</City>
    <NewCustomer>N</NewCustomer>
  </Customer>
  <Customer>
    <CustomerID>1113</CustomerID>
    <CompanyName>Institute of Art</CompanyName>
    <City>Chicago</City>
    <NewCustomer>Y</NewCustomer>
  </Customer>
</CustomerList>

这是转换样式表。

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

  <!-- Identity Template (applies to all nodes and will copy all nodes -->
  <xsl:template match="@* | node()">
    <xsl:copy>
      <xsl:apply-templates select="@* | node()"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="Customer">
    <xsl:choose>
      <xsl:when test="NewCustomer = 'Y'">
        <xsl:text>true</xsl:text>
      </xsl:when>
      <xsl:when test="NewCustomer = 'N'">
        <xsl:text>false</xsl:text>
      </xsl:when>
    </xsl:choose>
  </xsl:template>

</xsl:stylesheet>

这是我的输出。

  <?xml version="1.0" encoding="utf-8" ?> 
  <CustomerList>false false true</CustomerList> 

这就是我想要输出的内容。

<?xml version="1.0"?>
<CustomerList>
  <Customer>
    <CustomerID>1111</CustomerID>
    <CompanyName>Sean Chai</CompanyName>
    <City>New York</City>
    <NewCustomer>false</NewCustomer>
  </Customer>
  <Customer>
    <CustomerID>1112</CustomerID>
    <CompanyName>Tom Johnston</CompanyName>
    <City>Los Angeles</City>
    <NewCustomer>false</NewCustomer>
  </Customer>
  <Customer>
    <CustomerID>1113</CustomerID>
    <CompanyName>Institute of Art</CompanyName>
    <City>Chicago</City>
    <NewCustomer>true</NewCustomer>
  </Customer>
</CustomerList>

我想念的是什么?为什么?我看到如果我省略了检查NewCustomer的子句,整个输出就会输出。但是,选择为NewCustomer输出正确更改的值只会显示它们。是否有对我必须在第二个模板中创建的上一个模板的引用?

3 个答案:

答案 0 :(得分:4)

Jim Garrison将删除任何包含它们的NewCustomer元素的属性。正如他所说的那样,Tomalak有点脏。

此版本几乎是您对XSLT的要求的字面翻译:

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

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

  <xsl:template match="NewCustomer/text()[.='Y']">
   <xsl:text>true</xsl:text>
  </xsl:template>

 <xsl:template match="NewCustomer/text()[.='N']">
    <xsl:text>false</xsl:text>
  </xsl:template>

</xsl:stylesheet>

源树中唯一没有完全复制到结果集中的节点是文本节点,它们是NewCustomer元素的子元素,其值为YN ;对于那些,它分别发出truefalse

答案 1 :(得分:3)

通过让您的模板与Customer匹配,您将拦截该标记的所有处理。

尝试更改模板以仅匹配NewCustomer,在测试条件中进行相应的更改(test =“。='Y'”)。

另请注意,您必须在输出中创建NewCustomer标记,因为通过在自定义模板中对其进行匹配,它不会被标识转换处理。你很亲密。

这是更新后的模板:

<xsl:template match="Customer/NewCustomer">
    <xsl:copy>
        <xsl:choose>
            <xsl:when test=". = 'Y'">
                <xsl:text>true</xsl:text>
            </xsl:when>
            <xsl:when test=". = 'N'">
                <xsl:text>false</xsl:text>
            </xsl:when>
        </xsl:choose>
    </xsl:copy>
</xsl:template>

首先,它与NewCustomer匹配为Customer的子级。然后,它使用xsl:copy来创建节点的副本(但不是属性或子节点)。然后它使用你的xsl:选择将N和Y值分别转换为false和true。

关键概念是当模板与输入元素匹配时,输入元素将从输出中有效删除,并替换为匹配模板的内容。在您与Customer匹配的情况下,Customer标记及其中的所有内容都替换为模板的内容,该模板只生成“true”或“false”。

答案 2 :(得分:0)

吉姆加里森的答案中的好解释仍然适用。这是一种浓缩/替代方法:

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

  <xsl:template match="@* | node()">
    <xsl:copy>
      <xsl:choose>
        <xsl:when test="self::NewCustomer">
          <xsl:value-of select="boolean(number(translate(., 'YN', '10')))" />
        </xsl:when>
        <xsl:otherwise>
          <xsl:apply-templates select="@* | node()"/>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:copy>
  </xsl:template>
</xsl:stylesheet>

表达式boolean(number(translate(., 'YN', '10')))'Y'更改为'1'并将'N'更改为'0',然后将其首先转换为数字,然后转换为布尔值。布尔值将分别表示为'true''false'

这有点脏,因为它并不真正处理'Y''N'以外的值 - 但它会为'false'以外的任何值输出'Y'

这只是一个节省空间。如果你愿意,你可以用像Jim Garrison这样的<xsl:choose>替换它。