0
votes

This one is for all you XPath and XSLT geniuses!

This is an extract from an XLIFF file where I need to delete the text between tags where an attribute value matches any of an array of id numbers, but importantly only if it is within certain tag boundaries, the <target> tags to be precise.

This may be a simple task for XSLT and one of you gurus, but it's about my last resort now having struggled with trying to process this with Perl which was not reliable enough due to struggles with positive and negative lookarounds over multiple lines.

For example ( see fuller example lower down) in the snippet below I need to remove the text between the <emp> tags where pid="569" and pid= "570" but only if it is nested within the <target> tags. The identical text within the <alt-source<t><emp> tree that also have pid ="569" and pid="570" must be left intact.

            <alt-source>
                    <t id="4507">
                        <emp ptype="para" pid="569">Q27a.</emp>
                        <emp ptype="para" pid="570">
                            <t id="4516">Before 1996</t><t id="4537"> [this/that] </t>did not exist</emp>
                    </t>
                </alt-source>
                <target>
                    <t id="4507">
                        <emp ptype="para" pid="569">Q27a.</emp>
                        <emp ptype="para" pid="570">
                            <t id="4516">Before 1996</t><t id="4537"> [this/that] </t>did not exist</emp>
                    </t>
                </target>

Note that the text within can also have embedded tags and there may be whitespace differences. There can be more than one "matchable" item in the <target> tree, as in the final <igroup> below. The file could have several thousand of these igroup nodes, and the igroups are not the top level.

For example in the array of pids we have [569 570 587] so only those <target> nodes where <emp> has an attribute "pid" that matches those pids need to be processed. The inner text must be removed including any embedded tags leaving just <emp ptype="para" pid="587"></emp> for example.

Is this even possible with XSLT?

Any help would be greatly appreciated!

            <igroup>
                <source>
                    <t id="4612">3 times per day or more</t>
                </source>
                <alt-source>
                    <t id="4612">
                        <emp ptype="para" pid="585">3 times per day or more</emp>
                    </t>
                </alt-source>
                <target>
                    <t id="4612">
                        <emp ptype="para" pid="585">3 fois par jour ou plus</emp>
                    </t>
                </target>
            <igroup>
            <igroup>
                <source>
                    <t id="4507">Q27a. </t><t id="4516">Before 1996</t><t id="4537"> [this/that] </t>did not exist</emp>
                </source>
                <alt-source>
                    <t id="4507">
                        <emp ptype="para" pid="569">Q27a.</emp>
                        <emp ptype="para" pid="570">
                            <t id="4516">Before 1996</t><t id="4537"> [this/that] </t>did not exist</emp>
                    </t>
                </alt-source>
                <target>
                    <t id="4507">
                        <emp ptype="para" pid="569">Q27a.</emp>
                        <emp ptype="para" pid="570">
                            <t id="4516">Before 1996</t><t id="4537"> [this/that] </t>did not exist</emp>
                    </t>
                </target>
            </igroup>
            <igroup>
                <source>a.</source>
                <alt-source>
                    <emp ptype="para" pid="586">a.</emp>
                    <emp ptype="para" pid="587">b.</emp>
                    <emp ptype="para" pid="588">c.</emp>
                </alt-source>
                <target>
                    <emp ptype="para" pid="586">a.</emp>
                    <emp ptype="para" pid="587">b.</emp>
                    <emp ptype="para" pid="588">c.</emp>
                </target>
            </igroup>
1
I don't understand your question. Seeing the expected output might help, but your terminology is all wrong. For example, text cannot have "embedded tags". -- P.S. Please state if using XSLT 1.0 or 2.0. - michael.hor257k
Hi Michael, Thank you for looking and apologies if my terminology is not correct - I am not experienced with XPath or XSLT. When I say there are embedded tags, have a look at the structure above for the t tags that are inside the emp tags. That's what I meant. XSLT 1.0 or 2.0 can be used , I will be running this inside a Perl script. - user3012857

1 Answers

2
votes

I believe I get what you want.

You example XML had problems so I had to adjust it.

You can use // which can be used to skip levels.

XSLT:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <!-- this copies all other elements -->
  <xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>

  <!-- this intercepts our specific elements -->
  <xsl:template match="target//emp[@pid='569' or @pid='570' or @pid='587']">
    <!-- this copies element name -->
    <xsl:copy>
      <!-- this copies all its attributes -->
      <xsl:copy-of select="@*"/>
    </xsl:copy>
  </xsl:template>
</xsl:stylesheet>

Edited XML:

<igroup>
  <source>
    <t id="4612">3 times per day or more</t>
  </source>
  <alt-source>
    <t id="4612">
      <emp ptype="para" pid="585">3 times per day or more</emp>
    </t>
  </alt-source>
  <target>
    <t id="4612">
      <emp ptype="para" pid="585">3 fois par jour ou plus</emp>
    </t>
  </target>
  <igroup>
    <igroup>
      <source>
        <emp ptype="para" pid="570">
          <t id="4507">Q27a. </t>
          <t id="4516">Before 1996</t>
          <t id="4537"> [this/that] </t>
          did not exist
        </emp>
      </source>
      <alt-source>
        <t id="4507">
          <emp ptype="para" pid="569">Q27a.</emp>
          <emp ptype="para" pid="570">
            <t id="4516">Before 1996</t>
            <t id="4537"> [this/that] </t>
            did not exist
          </emp>
        </t>
      </alt-source>
      <target>
        <t id="4507">
          <emp ptype="para" pid="569">Q27a.</emp>
          <emp ptype="para" pid="570">
            <t id="4516">Before 1996</t>
            <t id="4537"> [this/that] </t>
            did not exist
          </emp>
        </t>
      </target>
    </igroup>
    <igroup>
      <source>a.</source>
      <alt-source>
        <emp ptype="para" pid="586">a.</emp>
        <emp ptype="para" pid="587">b.</emp>
        <emp ptype="para" pid="588">c.</emp>
      </alt-source>
      <target>
        <emp ptype="para" pid="586">a.</emp>
        <emp ptype="para" pid="587">b.</emp>
        <emp ptype="para" pid="588">c.</emp>
      </target>
    </igroup>
  </igroup>
</igroup>

Result:

<?xml version="1.0" encoding="utf-8"?><igroup>
  <source>
    <t id="4612">3 times per day or more</t>
  </source>
  <alt-source>
    <t id="4612">
      <emp ptype="para" pid="585">3 times per day or more</emp>
    </t>
  </alt-source>
  <target>
    <t id="4612">
      <emp ptype="para" pid="585">3 fois par jour ou plus</emp>
    </t>
  </target>
  <igroup>
    <igroup>
      <source>
        <emp ptype="para" pid="570">
          <t id="4507">Q27a. </t>
          <t id="4516">Before 1996</t>
          <t id="4537"> [this/that] </t>
          did not exist
        </emp>
      </source>
      <alt-source>
        <t id="4507">
          <emp ptype="para" pid="569">Q27a.</emp>
          <emp ptype="para" pid="570">
            <t id="4516">Before 1996</t>
            <t id="4537"> [this/that] </t>
            did not exist
          </emp>
        </t>
      </alt-source>
      <target>
        <t id="4507">
          <emp ptype="para" pid="569" />
          <emp ptype="para" pid="570" />
        </t>
      </target>
    </igroup>
    <igroup>
      <source>a.</source>
      <alt-source>
        <emp ptype="para" pid="586">a.</emp>
        <emp ptype="para" pid="587">b.</emp>
        <emp ptype="para" pid="588">c.</emp>
      </alt-source>
      <target>
        <emp ptype="para" pid="586">a.</emp>
        <emp ptype="para" pid="587" />
        <emp ptype="para" pid="588">c.</emp>
      </target>
    </igroup>
  </igroup>
</igroup>