使用XSLT Concat类似的XML标记值

时间:2012-06-20 10:46:35

标签: xml xslt

我如何处理这个问题,以便在XML文件中连接类似的XML标签

我有以下格式的XMl ::

<addressbook>
 <address>
    <first-name>Chester Hasbrouck</first-name>
     <Descritpion>Hi</Descritpion>
     <Descritpion>This is Chester </Descritpion>
   <street>1234 Main Street</street>
  <city>Sheboygan</city>
  <state>WI</state>
  <zip>48392</zip>
 </address>
 <address>
    <first-name>Mary</first-name>
     <Descritpion>Hi</Descritpion>
     <Descritpion>This is Mary </Descritpion>
     <Descritpion>Bye</Descritpion>
     <street>283 First Avenue</street>
  <city>Skunk Haven</city>
  <state>MA</state>
  <zip>02718</zip>
 </address>
</addressbook>

我需要以下面的格式,有人请为此建议XSLT。

<addressbook>
 <address>
    <first-name>Chester Hasbrouck</first-name>
     <Descritpion>Hi | This is Chester </Descritpion>
   <street>1234 Main Street</street>
  <city>Sheboygan</city>
  <state>WI</state>
  <zip>48392</zip>
 </address>
 <address>
    <first-name>Mary</first-name>
     <Descritpion>Hi | This is Mary | Bye</Descritpion>
     <street>283 First Avenue</street>
  <city>Skunk Haven</city>
  <state>MA</state>
  <zip>02718</zip>
 </address>
</addressbook>

3 个答案:

答案 0 :(得分:1)

此转化

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

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

 <xsl:template match="Descritpion[not(preceding-sibling::*[1][self::Descritpion])]">
  <Descritpion>
   <xsl:value-of select="."/>
   <xsl:apply-templates select="following-sibling::Descritpion/text()"/>
  </Descritpion>
 </xsl:template>

 <xsl:template match="Descritpion/text()">
   <xsl:value-of select="concat(' | ', .)"/>
 </xsl:template>
 <xsl:template match="Descritpion"/>
</xsl:stylesheet>

应用于提供的XML文档时:

<addressbook>
    <address>
        <first-name>Chester Hasbrouck</first-name>
        <Descritpion>Hi</Descritpion>
        <Descritpion>This is Chester </Descritpion>
        <street>1234 Main Street</street>
        <city>Sheboygan</city>
        <state>WI</state>
        <zip>48392</zip>
    </address>
    <address>
        <first-name>Mary</first-name>
        <Descritpion>Hi</Descritpion>
        <Descritpion>This is Mary </Descritpion>
        <Descritpion>Bye</Descritpion>
        <street>283 First Avenue</street>
        <city>Skunk Haven</city>
        <state>MA</state>
        <zip>02718</zip>
    </address>
</addressbook>

生成想要的正确结果

<addressbook>
   <address>
      <first-name>Chester Hasbrouck</first-name>
      <Descritpion>Hi | This is Chester </Descritpion>
      <street>1234 Main Street</street>
      <city>Sheboygan</city>
      <state>WI</state>
      <zip>48392</zip>
   </address>
   <address>
      <first-name>Mary</first-name>
      <Descritpion>Hi | This is Mary  | Bye</Descritpion>
      <street>283 First Avenue</street>
      <city>Skunk Haven</city>
      <state>MA</state>
      <zip>02718</zip>
   </address>
</addressbook>

<强>解释

  1. 身份规则“按原样”复制每个节点。

  2. 通过使用与Descritpion匹配的空体模板覆盖身份模板,通常会忽略/删除
  3. Descritpion元素。

  4. 只有Descritpion元素的前一个兄弟元素不是Descritpion本身才会被另一个覆盖模板专门处理。这里复制元素的字符串值,然后将模板应用于以下兄弟Descritpion元素的所有text-node-children。

  5. 匹配Descritpion元素的text-node-child的模板实现了有用的文本连接。

答案 1 :(得分:0)

要做到这一点,你可以建立身份变换,但添加额外的规则来处理你感兴趣的元素

我认为您首先需要匹配其中没有子元素的元素

<xsl:template match="*[not(*)]" priority="1">

然后,您可以向此处添加代码以输出当前文本值,然后选择具有相同名称的所有后续兄弟姐妹的文本值(将使用之前的分隔符输出)

<xsl:apply-templates 
   select="following-sibling::*[local-name() = local-name(current())]/text()" 
   mode="concat"/>

您还需要添加一个模板来忽略与前一个兄弟同名的元素,这样它们就不会输出两次

<xsl:template 
    match="*[not(*)][local-name() = local-name(preceding-sibling::*[1])]" 
    priority="2" />

请注意此处使用优先级属性,因此XSLT处理器首先匹配优先级较高的处理器。

这是完整的XSLT

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

   <xsl:template match="*[not(*)]" priority="1">
      <xsl:copy>
         <xsl:value-of select="normalize-space(.)"/>
         <xsl:apply-templates select="following-sibling::*[local-name() = local-name(current())]/text()" mode="concat"/>
      </xsl:copy>
   </xsl:template>

   <xsl:template match="*[not(*)][local-name() = local-name(preceding-sibling::*[1])]" priority="2"/>

   <xsl:template match="text()" mode="concat">
      <xsl:value-of select="concat(' | ', normalize-space(.))"/>
   </xsl:template>

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

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

<addressbook>
   <address>
      <first-name>Chester Hasbrouck</first-name>
      <Descritpion>Hi | This is Chester</Descritpion>
      <street>1234 Main Street</street>
      <city>Sheboygan</city>
      <state>WI</state>
      <zip>48392</zip>
   </address>
   <address>
      <first-name>Mary</first-name>
      <Descritpion>Hi | This is Mary | Bye</Descritpion>
      <street>283 First Avenue</street>
      <city>Skunk Haven</city>
      <state>MA</state>
      <zip>02718</zip>
   </address>
</addressbook>

答案 2 :(得分:0)

这是另一种方法。

有一点需要注意:此解决方案不维护输出文档排序(即,它不会直接在<Descritpion>元素下创建新的<first-name>元素)。如果这对您很重要,请查看其他提供的解决方案。

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  <xsl:output omit-xml-declaration="no" indent="yes"/>
  <xsl:strip-space elements="*"/>

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

  <!-- TEMPLATE #2 -->
  <xsl:template match="address">
    <xsl:copy>
      <xsl:apply-templates/>
      <Descritpion>
        <xsl:apply-templates select="Descritpion/text()"/>
      </Descritpion>
    </xsl:copy>
  </xsl:template>

  <!-- TEMPLATE #3 -->
  <xsl:template match="Descritpion/text()">
    <xsl:value-of select="." />
    <xsl:if test="position() != last()"> | </xsl:if>    
  </xsl:template>

  <!-- TEMPLATE #4 -->
  <xsl:template match="Descritpion" />
</xsl:stylesheet>

在提供的XML文档上提供此内容时:

<?xml version="1.0" encoding="UTF-8"?>
<addressbook>
  <address>
    <first-name>Chester Hasbrouck</first-name>
    <Descritpion>Hi</Descritpion>
    <Descritpion>This is Chester </Descritpion>
    <street>1234 Main Street</street>
    <city>Sheboygan</city>
    <state>WI</state>
    <zip>48392</zip>
  </address>
  <address>
    <first-name>Mary</first-name>
    <Descritpion>Hi</Descritpion>
    <Descritpion>This is Mary </Descritpion>
    <Descritpion>Bye</Descritpion>
    <street>283 First Avenue</street>
    <city>Skunk Haven</city>
    <state>MA</state>
    <zip>02718</zip>
  </address>
</addressbook>

...产生了所需的结果:

<?xml version="1.0" encoding="UTF-8"?><addressbook>
  <address>
    <first-name>Chester Hasbrouck</first-name>
    <street>1234 Main Street</street>
    <city>Sheboygan</city>
    <state>WI</state>
    <zip>48392</zip>
    <Descritpion>Hi | This is Chester </Descritpion>
  </address>
  <address>
    <first-name>Mary</first-name>
    <street>283 First Avenue</street>
    <city>Skunk Haven</city>
    <state>MA</state>
    <zip>02718</zip>
    <Descritpion>Hi | This is Mary  | Bye</Descritpion>
  </address>
</addressbook>

<强>解释

  • 模板#1:“身份模板”按原样复制所有内容。

  • 模板#2:此模板按原样复制每个<address>元素,创建新的<Descritpion>元素,并指示XSLT处理器填充该元素包含与Descritpion/text()匹配的任何模板的结果的新元素。

  • 模板#3:此模板处理模板#2的结果;特别是,它复制了所有旧<Descritpion>元素中的文本,并且在到达最后一个元素之前,在结果之间放置了|

  • 模板#4:此模板会从源文档中删除原始<Descritpion>元素。