简体   繁体   中英

Modify xml document using XSLT

I am trying to understand if there is a way to modify an xml document using XSLT or are there any other better approaches than XSLT?

Say, I have an xml like so:

<feed xmlns="http://www.w3.org/2005/Atom">
<id>http://libx.org/libx2/libapps</id>
<entry>
<id>http://libx.org/libx2/libapps/2</id>
</entry>
<entry>
<id>http://libx.org/libx2/libapps/3</id>
</entry>
</feed>

I would like to do the following actions:

  1. Modify feed:id to (remove the text of feed:id)
  2. Modify entry:id values such that the last number value after "/" remains.

The result xml should look something like so:

<feed xmlns="http://www.w3.org/2005/Atom">
<id></id>
<entry>
<id>2</id>
</entry>
<entry>
<id>3</id>
</entry>
</feed>

Thanks, Sony

I. XSLT 1.0 solution:

This XSLT 1.0 transformation works with any url without having any assumptions about all URLs haing a common starting substring:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:x="http://www.w3.org/2005/Atom">
 <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="x:feed/x:id/node()"/>

 <xsl:template match="x:entry/x:id/text()" name="eatSlashes">
  <xsl:param name="pText" select="."/>

  <xsl:choose>
   <xsl:when test="not(contains($pText, '/'))">
    <xsl:value-of select="$pText"/>
   </xsl:when>
   <xsl:otherwise>
    <xsl:call-template name="eatSlashes">
     <xsl:with-param name="pText" select=
                   "substring-after($pText, '/')"/>
    </xsl:call-template>
   </xsl:otherwise>
  </xsl:choose>
 </xsl:template>
</xsl:stylesheet>

when applied on the provided XML document :

<feed xmlns="http://www.w3.org/2005/Atom">
    <id>http://libx.org/libx2/libapps</id>
    <entry>
        <id>http://libx.org/libx2/libapps/2</id>
    </entry>
    <entry>
        <id>http://libx.org/libx2/libapps/3</id>
    </entry>
</feed>

the wanted, correct result is produced :

<feed xmlns="http://www.w3.org/2005/Atom">
   <id/>
   <entry>
      <id>2</id>
   </entry>
   <entry>
      <id>3</id>
   </entry>
</feed>

II. XSLT 2.0 solution :

<xsl:stylesheet version="2.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:x="http://www.w3.org/2005/Atom">
 <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="x:feed/x:id/node()"/>

 <xsl:template match="x:entry/x:id/text()">
  <xsl:sequence select="tokenize(.,'/')[last()]"/>
 </xsl:template>
</xsl:stylesheet>

when applied on the same XML document (above), the same correct result is produced :

<feed xmlns="http://www.w3.org/2005/Atom">
   <id/>
   <entry>
      <id>2</id>
   </entry>
   <entry>
      <id>3</id>
   </entry>
</feed>

My knowledge of XSLT isn't the best but this seems to work:

<?xml version="1.0" encoding="utf-8"?>
<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="a:feed/a:id" xmlns:a="http://www.w3.org/2005/Atom">
    <xsl:copy/>
  </xsl:template>
  <xsl:template match="a:entry/a:id" xmlns:a="http://www.w3.org/2005/Atom">
    <xsl:copy><xsl:value-of select="substring-after(.,'http://libx.org/libx2/libapps/')"/></xsl:copy>
  </xsl:template>

</xsl:stylesheet>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM