Filter XML based on another xml using XSLT 1

How do we filter an XML document based on another xml document. I have to remove all elements that are not in lookum xml. Both the original xml and lookup xml have the same root elements, we use XSLT 1.0.

Ex input

<Root>
    <E1 a="1">V1</E1>
    <E2>V2</E2>
    <E3>V3</E3>
    <E5>
       <SE51>SEV1</SE51>    
       <SE52>SEV2</SE52>    
    </E5>
    <E6>
       <SE61>SEV3</SE61>    
       <SE62>SEV4</SE62>    
    </E6>
</Root>

Xml filter

<Root>
    <E1 a="1"></E1>
    <E2></E2>
    <E5>
       <SE51></SE51>    
       <SE52></SE52>    
    </E5>
</Root>

Expected Result

<Root>
    <E1 a="1">V1</E1>
    <E2>V2</E2>
    <E5>
       <SE51>SEv1</SE51>    
       <SE52>SEV2</SE52>    
    </E5>
</Root>
+2
source share
3 answers

Here is the required conversion:

<xsl: stylesheet version = "1.0"
 xmlns: xsl = "http://www.w3.org/1999/XSL/Transform"
 xmlns: z = "inline: text.xml"
 exclude-result-prefixes = "z"
 >
    <xsl: output omit-xml-declaration = "yes" indent = "yes" />
    <xsl: strip-space elements = "*" />

    <z: filter>
        <Root>
            <E1 a="1"></E1>
            <E2></E2>
            <E5>
                <SE51></SE51>
                <SE52></SE52>
            </E5>
        </Root>
    </z:filter>

    <xsl:variable name="vFilter" select=
     "document('')/*/z:filter"/>

    <xsl:template match="/">
      <xsl:apply-templates select="*[name()=name($vFilter/*)]">
        <xsl:with-param name="pFiltNode" select="$vFilter/*"/>
      </xsl:apply-templates>
    </xsl:template>

    <xsl:template match="*">
      <xsl:param name="pFiltNode"/>

      <xsl:copy>
       <xsl:copy-of select="@*"/>

       <xsl:for-each select="text() | *">
         <xsl:choose>
           <xsl:when test="self::text()">
             <xsl:copy-of select="."/>
           </xsl:when>
           <xsl:otherwise>
            <xsl:variable name="vFiltNode"
                 select="$pFiltNode/*[name()=name(current())]"/>

            <xsl:apply-templates select="self::node()[$vFiltNode]">
              <xsl:with-param name="pFiltNode" select="$vFiltNode"/>
            </xsl:apply-templates>
           </xsl:otherwise>
         </xsl:choose>
       </xsl:for-each>
      </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

XML ( <SE511>SEV11</SE511> , :

<Root>
    <E1 a="1">V1</E1>
    <E2>V2</E2>
    <E3>V3</E3>
    <E5>
        <SE51>SEV1</SE51>
        <SE511>SEV11</SE511>
        <SE52>SEV2</SE52>
    </E5>
    <E6>
        <SE61>SEV3</SE61>
        <SE62>SEV4</SE62>
    </E6>
</Root>

:

<Root>
    <E1 a="1">V1</E1>
    <E2>V2</E2>
    <E3>V3</E3>
    <E5>
        <SE51>SEV1</SE51>
        <SE511>SEV11</SE511>
        <SE52>SEV2</SE52>
    </E5>
    <E6>
        <SE61>SEV3</SE61>
        <SE62>SEV4</SE62>
    </E6>
</Root>

:

  • , node -, .
  • , , node -.
  • - node .

!

+3

, ( , doc ). , , . ?

google "xslt + merge" , - .

0

, , , :

  • Write the conversion in XSLT to which the "XML filter" is consumed, and perform the conversion (also in XSLT).
  • Run the resulting XSLT on your input.

It sounds (and is) ugly, but I found it easier than trying to interpret the filter description on the fly when converting input.

0
source

Source: https://habr.com/ru/post/1705175/


All Articles