Make new node using sub-node sub-string

2019-09-06 13:39发布

I have an xml document that looks like this:

<oldEle userlabel="label1">
  <ele1>%02d.jpeg</ele1>
</oldEle>

<oldEle userlabel="label2">
  <ele1>%02d.tiff</ele1>
</oldEle>

I want it to be this:

<JPEG userlabel="label1">
  <ele1>%02d.jpeg</ele1>
</JPEG>

<TIFF userlabel="label2">
  <ele1>%02d.tiff</ele1>
</TIFF>

I've tried this.

<xsl:template match="//xmlns:oldNode[contains(//xmlsns:oldNode/root:ele1, '.')]">
  <xsl:element name="{translate(substring-after(//xmlns:ele1, '.'),
               'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ')}">
      <xsl:apply-templates select="@*|node()"/>
  </xsl:element>
</xsl:template>

but only get the first of the file ext. e.g. if jpeg is first, I would get for both of the nodes. Could someone offer expertise advice on why this is not working.

BTW, I also tried this but same thing happened:

<xsl:template match="//xmlns:oldNode[contains(//root:ele1, '.jpeg')]">
  <xsl:element name="JPEG">
      <xsl:apply-templates select="@*|node()"/>
  </xsl:element>
</xsl:template>

<xsl:template match="//xmlns:oldNode[contains(//root:ele1, '.tiff')]">
  <xsl:element name="TIFF">
      <xsl:apply-templates select="@*|node()"/>
  </xsl:element>
</xsl:template>

标签: xslt xslt-1.0
3条回答
▲ chillily
2楼-- · 2019-09-06 14:17

Here is the same answer as to your previous question -- this solves completely the old and the current problem and no recursion is used:

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

     <my:suffixes>
      <s>jpeg</s><s>JPEG</s>
      <s>tiff</s><s>TIFF</s>
      <s>giv</s><s>GIV</s>
      <s>png</s><s>PNG</s>
     </my:suffixes>

     <xsl:variable name="vSufs" select="document('')/*/my:suffixes/s"/>

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

     <xsl:template match="*">
       <xsl:variable name="vSufFound" select=
        "$vSufs[position() mod 2 = 1]
             [substring(translate(current()/ele1, ., ''),
                        string-length(translate(current()/ele1, ., ''))
                        )
             =
              '.'
             ]"/>
       <xsl:choose>
         <xsl:when test="not($vSufFound)">
          <xsl:call-template name="identity"/>
         </xsl:when>
         <xsl:otherwise>
           <xsl:element name="{$vSufFound/following-sibling::s[1]}">
             <xsl:apply-templates select="node()|@*"/>
           </xsl:element>
         </xsl:otherwise>
       </xsl:choose>
     </xsl:template>
</xsl:stylesheet>

When this transformation is applied on the provided XML document, the wanted, correct result is produced:

<t>
    <JPEG userlabel="label1">
        <ele1>%02d.jpeg</ele1>
    </JPEG>
    <TIFF userlabel="label2">
        <ele1>%02d.tiff</ele1>
    </TIFF>
</t>

Explanation:

In this transformation we are using the following XPath 1.0 expression to implement the standard XPath 2.0 ends-with($t, $suf) function:

$suf = substring($t, string-length($t) - string-length($suf) +1)
查看更多
叛逆
3楼-- · 2019-09-06 14:30

The first problem is with your matching template

 <xsl:template match="//xmlns:oldNode[contains(//xmlsns:oldNode/root:ele1, '.')]">

In particular, with the contains element you probably don't want the //oldNode at the front, as this will start looking for the first oldNode relative to the root element. What you really want is to look for the ele1 element relative to the element you have currently matched

<xsl:template match="//oldNode[contains(ele1, '.')]">

(I am not sure if you mean oldNode or oldEle by the way. I am also not sure where your namespaces fit in, so I have not shown them here).

The second problem is with the xsl:element, as you are doing a similar thing here

<xsl:element name="{translate(substring-after(//xmlns:ele1, '.'),         
    'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ')}">   

Because of the // in the substring-after, it will pick up the first ele1 relative to the root element of the XML, and not the one relative to your current element. You probably need to do this

<xsl:element name="{translate(substring-after(ele1, '.'),         
    'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ')}">  

Try this template instead

<xsl:template match="//oldNode[contains(ele1, '.')]">            
    <xsl:element name="{translate(substring-after(//ele1, '.'),            
           'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ')}">            
       <xsl:apply-templates select="@*|node()"/>            
    </xsl:element>            
</xsl:template>   

Similarly, for you second set of templates, you should be doing something like this

<xsl:template match="//oldNode[contains(ele1, '.jpeg')]"> 
查看更多
狗以群分
4楼-- · 2019-09-06 14:39
<xsl:template match="oldNode">
    <xsl:choose>
        <xsl:when test="contains(ele1,'.jpeg')">
            <xsl:element name="JPEG">
                <xsl:apply-templates select="@*|node()"/>
            </xsl:element>
        </xsl:when>
        <xsl:when test="contains(ele1,'.tiff')">
            <xsl:element name="TIFF">
                <xsl:apply-templates select="@*|node()"/>
            </xsl:element>
        </xsl:when>
    </xsl:choose>
</xsl:template>
查看更多
登录 后发表回答