using XSL to replace XML nodes with new nodes

后端 未结 3 633
旧时难觅i
旧时难觅i 2020-12-14 22:39

I need an XSL solution to replace XML nodes with new nodes.

Say I have the following existing XML structure:


    
               


        
相关标签:
3条回答
  • 2020-12-14 23:29

    Here is one correct solution, which is probably one of the shortest:

     <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="criterion[. = 'AAA']">
      <criterion>BBB</criterion>
      <criterion>CCC</criterion>
      <criterion>DDD</criterion> </xsl:template>
    </xsl:stylesheet>
    

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

    <root>
        <criteria>
            <criterion>BBB</criterion>
            <criterion>CCC</criterion>
            <criterion>DDD</criterion>
        </criteria>
    </root>
    

    Do note:

    1. The use of the identity template.

    2. How the identity template is overriden by a specific template -- only for a criterion element, whose string value is 'AAA'.

    0 讨论(0)
  • 2020-12-14 23:33

    XSL cannot replace anything. The best you can do is to copy the parts you want to keep, then output the parts you want to change instead of the parts you don't want to keep.


    Example:

    <?xml version="1.0" encoding="utf-8"?>
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl"
    >
        <xsl:output method="xml" indent="yes"/>
    
        <!-- This is an identity template - it copies everything
             that doesn't match another template -->
        <xsl:template match="@* | node()">
            <xsl:copy>
                <xsl:apply-templates select="@* | node()"/>
            </xsl:copy>
        </xsl:template>
    
      <!-- This is the "other template". It says to use your BBB-DDD elements
           instead of the AAA element -->
      <xsl:template match="criterion[.='AAA']">
        <xsl:element name="criterion">
          <xsl:text>BBB</xsl:text>
        </xsl:element>
        <xsl:element name="criterion">
          <xsl:text>CCC</xsl:text>
        </xsl:element>
        <xsl:element name="criterion">
          <xsl:text>DDD</xsl:text>
        </xsl:element>
      </xsl:template>
    </xsl:stylesheet>
    

    The template match @* | node() matches any attribute or any other kind of node. The trick is that template matches have priorities. You can think of the rule as being "the more specific match wins". Anything is going to be more specific than "any attribute or other node". This makes the "identity" match a very low priority.

    When it is matched, it simply copies any nodes it finds inside the matched attribute or node.

    Any other templates you have will have a higher priority. Whatever they match, it's the code inside the more specific template that will have effect. For example, if you simply removed everything inside of the criterion[.='AAA'] template, you'd find that you had copied your input exactly, except for the "AAA" element.

    0 讨论(0)
  • 2020-12-14 23:43

    Under the general rule of more-than-one-way-to-skin-a-cat

    <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
        <xsl:output method="xml"/>
        <xsl:template match="/">
            <xsl:apply-templates />
        </xsl:template>
        <!--  
            when you capture a node with the text 'AAA'
                emit the BBB, CCC, DDD nodes
         -->
        <xsl:template match="criterion[text() = 'AAA']">
            <xsl:element name="criterion">
                <xsl:text>BBB</xsl:text>
            </xsl:element>
            <xsl:element name="criterion">
                <xsl:text>CCC</xsl:text>
            </xsl:element>
            <xsl:element name="criterion">
                <xsl:text>DDD</xsl:text>
            </xsl:element>
        </xsl:template>
        <!--  identity template  -->
        <xsl:template match="@*|node()">
          <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
          </xsl:copy>
        </xsl:template>
    </xsl:stylesheet>
    
    0 讨论(0)
提交回复
热议问题