Matching Nearby Parent Elements

Viewed 35

I'm trying to match some of the nearby parent elements of a specific node.
So basically

  1. Find all nodes containing TESTWORD
  2. Match 1 parent node before AND 3 parents after
  3. Replace with another node

Input:

<!-- ... -->
  <w:p>
      <w:pPr>
          Text ...
      </w:pPr>
      <w:r>
          <w:rPr/>
          <w:t xml:space="preserve">More text...</w:t>
      </w:r>
      

      <!-- REMOVE FROM HERE -->
      <w:r>
          <w:rPr/>
          <w:fldChar w:fldCharType="begin"/>
      </w:r>
      <w:r>
          <w:rPr/>
          <w:instrText> TESTWORD </w:instrText>
      </w:r>
      <w:r>
          <w:rPr/>
          <w:fldChar w:fldCharType="separate"/>
      </w:r>
      <w:r>
          <w:rPr/>
          <w:t>Even more text...</w:t>
      </w:r>
      <w:r>
          <w:rPr/>
          <w:fldChar w:fldCharType="end"/>
      </w:r>
      <!-- REMOVE UNTIL HERE -->

  </w:p>
<!-- ... -->

Desired output:

<!-- ... -->
  <w:p>
      <w:pPr>
          Text ...
      </w:pPr>
      <w:r>
          <w:rPr/>
          <w:t xml:space="preserve">More text...</w:t>
      </w:r>

        <!-- INSERT NEW ELEMENTS FROM HERE -->
        <w:r>
            <w:rPr></w:rPr>
            <w:t>New text</w:t>
        </w:r>
       <!-- INSERT NEW ELEMENTS UNTIL HERE -->

  </w:p>
<!-- ... -->

This is my approach:

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

    <xsl:param name="newText" select="New Text" />

    <xsl:template match="node()|@*">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*" />
        </xsl:copy>
    </xsl:template>
    
    <xsl:template match="*[.=' TESTWORD ']ancestor::*">
        <xsl:element name="w:rPr"></xsl:element>
        <xsl:element name="w:t">
            <xsl:value-of select="$newText" />
        </xsl:element>  
    </xsl:template>

</xsl:stylesheet>

But I get an error here:

'ancestor', '::', '*'
1 Answers
  • You are missing a / before ancestor:: in the match expression. However, you cannot use the ancestor:: axis in a match expression.
  • You have not declared the w namesapace prefix in your XSLT. This looks like Word markup, so assuming that it is xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" but update if not correct.
  • The parameter value <xsl:param name="newText" select="New Text" /> needs to be quoted <xsl:param name="newText" select="'New Text'" /> for the string literal value.

I would do something like this:

<xsl:stylesheet
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0"
    xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
    <xsl:output indent="yes" method="xml" encoding="utf-8" />
    
    <xsl:param name="newText" select="'New Text'" />
    <xsl:param name="oldText" select="' TESTWORD '" />
    
    <xsl:template match="node()|@*">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*" />
        </xsl:copy>
    </xsl:template>
    
    <xsl:template match="*/*[.=' TESTWORD ']">
        <xsl:element name="w:rPr"></xsl:element>
        <xsl:element name="w:t">
            <xsl:value-of select="$newText" />
        </xsl:element>  
    </xsl:template>
    
    <xsl:template match="*[following-sibling::*[1]/*[.=$oldText] | preceding-sibling::*[position() lt 4]/*[.=$oldText]]"/>
    
</xsl:stylesheet>
Related