filtering XML tags using XSLT

回眸只為那壹抹淺笑 提交于 2019-12-12 04:44:55

问题


I have the following XML code.

You will notice the tag Description is repeated, but with different attributes.

I am using XSLT to try and remove the Description tag with the enabled attribute.

<Batch>
- <Promotion>
  <LastUpdated>2008-01-22T11:58:05+00:00</LastUpdated> 
  <MajorVersion>1</MajorVersion> 
  <MinorVersion>29</MinorVersion> 
  <PromotionID>000873</PromotionID> 
  <Description enabled="1">*P* Free Mistletoe</Description> 
  <Description country="GB" language="en" variant="">WANTED LINE 1</Description>
 </Promotion>
 <Promotion>
   <LastUpdated>2008-01-22T11:58:05+00:00</LastUpdated> 
   <MajorVersion>1</MajorVersion> 
   <MinorVersion>29</MinorVersion> 
   <PromotionID>000874</PromotionID> 
   <Description enabled="1">*P* Free Mistletoe</Description> 
   <Description country="GB" language="en" variant="">WANTED LINE 2</Description>
 </Promotion> 
</batch>

This is what I am trying to get to, there are other tags, it is the removal of one line based on an attribute I am trying to resolve.

- <promotions>
-   <promotion>
      <promotionID>000873</promotionID> 
      <description country="GB" language="en" variant="">WANTED LINE 1</description>
    </promotion>
-   <promotion> 
      <promotionID>000874</promotionID> 
      <description country="GB" language="en" variant="">WANTED LINE 2</description>
    </promotion> 
  </promotions>

The XSLT code I am using is

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

<xsl:template match="node()|@*">
  <xsl:copy>
  <xsl:apply-templates select="node()|@*"/>
  </xsl:copy>
</xsl:template>
<xsl:template match="//promotion/Description[@country='GB']"/> 
<xsl:template match="/"> 

<promotions> 
<xsl:for-each select="Batch/Promotion">  
  <promotion>
    <promotion_id><xsl:value-of select="PromotionID"/></promotion_id>    
    <description><xsl:value-of select="Description"/></description>
  </promotion>
</xsl:for-each>   
</promotions>   
</xsl:template>
</xsl:stylesheet> 

If anyone could point me in the right direction I would be very grateful.

Paul


回答1:


Generally, in order to remove an element, you have to specify a template without any contents. In your case, this could be:

<xsl:template match="/Batch/Promotion/Description[@enabled = '1']"/>

In your XSLT code, however, you have the somewhat special case of constructing your own <description> element. In order to get exactly the value of the desired <Description> element, select it in your <xsl:value-of> element:

<description><xsl:value-of select="Description[@country = 'GB']"/></description>

This is what you have described in your question, however your expected result code implies that you already want to copy the attributes of the <Description> element? In that case, I'd go for this solution with <xsl:copy-of>:

<description><xsl:copy-of select="Description[@country = 'GB']/node()|Description[@country = 'GB']/@*"/></description>

It copies the whole contents of the <Description> element (node()), as well as any of its attributes (@*).




回答2:


try to use <xsl:value-of select="Description[not(string(@enabled))]"/> instead of <xsl:value-of select="Description"/>.

Full example:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="node()|@*">
    <xsl:copy>
        <xsl:apply-templates select="node()|@*"/>
    </xsl:copy>
</xsl:template>
<xsl:template match="//promotion/Description[@country='GB']"/>
<xsl:template match="/">
    <promotions>
        <xsl:for-each select="Batch/Promotion">
            <promotion>
                <promotion_id>
                    <xsl:value-of select="PromotionID"/>
                </promotion_id>
                <description>
                    <xsl:value-of select="Description[not(string(@enabled))]"/>
                </description>
            </promotion>
        </xsl:for-each>
    </promotions>
</xsl:template>

The result is:

<?xml version="1.0" encoding="UTF-16"?>
    <promotions>
    <promotion>
        <promotion_id>000873</promotion_id>
        <description>WANTED LINE 1</description>
    </promotion>
    <promotion>
        <promotion_id>000874</promotion_id>
        <description>WANTED LINE 2</description>
    </promotion>
</promotions>

Maybe it helps you.

Marco




回答3:


Instead of using for-each and value-of, consider using more templates instead.

Note the comments in the code below.

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

<xsl:template match="node()|@*">  <!-- identity template: copies everything by default -->
  <xsl:copy><xsl:apply-templates select="node()|@*"/></xsl:copy>
</xsl:template>

<!-- instead of an explicit for-each, just apply templates -->
<xsl:template match="/">
<promotions><xsl:apply-templates/></promotions>
</xsl:template>

<!-- We ignore Batch, but apply templates on contents -->
<xsl:template match="Batch"><xsl:apply-templates/></xsl:template>

<!-- Rename the Promotion element -->
<xsl:template match="Promotion">
<promotion><xsl:apply-templates/></promotion>
</xsl:template>

<!-- we make an exception for subelements of Promotion: here we delete by default -->
<!-- we give this template a lower priority so we can override it with other rules -->
<xsl:template match="Promotion/*" priority="-0.5"/>

<!-- The templates that follow are exceptions to the "Promotion/*" no-copy template: -->

<!-- Only copy Description elements with the right country code -->
<!-- Remember that the "Promotion/*" template will delete any other Description elements for us -->
<xsl:template match="Description[@country='GB']">
<description><xsl:apply-templates/></description>
</xsl:template>

<!-- Rename the PromotionID element -->
<xsl:template match="PromotionID">
   <promotion_id><xsl:apply-templates/></promotion_id>
</xsl:template>

</xsl:stylesheet> 


来源:https://stackoverflow.com/questions/11245346/filtering-xml-tags-using-xslt

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!