Apply XSLT on XML to filter information based on t

2019-08-07 06:11发布

I am new to XML and XSLT, I want to filter some information from an XML file. Based on match on some tag values in the XML file.

This is my XML File as follows:

<?xml version="1.0" encoding="UTF-8"?>
<People>
<Person>
    <required-tag1>some-information</required-tag1>
    <required-tag2>some-information</required-tag2>
    <tag3>not important info</tag3>
    <tag4>not important info</tag4>
    <first-name>Mike</first-name>
    <last-name>Hewitt</last-name>
    <licenses>
        <license>
            <number>938387</number>
            <state xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">TX</state>
            <field xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">Health</field>
        </license>
        <license>
            <number>938387</number>
            <state xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">IL</state>
            <field xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">Health</field>
        </license>
    </licenses>
    <appointments>
        <appointment-info>
            <code>5124</code>
            <number>14920329324</number>
            <licensed-states>
                <state>TX</state>
            </licensed-states>
        </appointment-info>
    </appointments>
</Person>
<Person>
    <required-tag1>some-information</required-tag1>
    <required-tag2>some-information</required-tag2>
    <tag3>not important info</tag3>
    <tag4>not important info</tag4>
    <first-name>John</first-name>
    <last-name>Jhonny</last-name>
    <licenses>
        <license>
            <number>1762539</number>
            <state xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">TX</state>
            <field xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">Health</field>
        </license>
        <license>
            <number>1762539</number>
            <state xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">NY</state>
            <field xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">Health</field>
        </license>
    </licenses>
    <appointments>
        <appointment-info>
            <code>5124</code>
            <number>14920329324</number>
            <licensed-states>
                <state>TX</state>
            </licensed-states>
        </appointment-info>
    </appointments>
</Person>
    <Person>
    <required-tag1>some-information</required-tag1>
    <required-tag2>some-information</required-tag2>
    <tag3>not important info</tag3>
    <tag4>not important info</tag4>
    <first-name>Mike</first-name>
    <last-name>Hewitt</last-name>
    <licenses>
        <license>
            <number>17294083</number>
            <state xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">IL</state>
            <field xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">Health</field>
        </license>
    </licenses>
    <appointments>
        <appointment-info>
            <code>5124</code>
            <number>14920329324</number>
            <licensed-states>
                <state>IL</state>
            </licensed-states>
        </appointment-info>
    </appointments>
</Person>
<Person>
    <required-tag1>some-information</required-tag1>
    <required-tag2>some-information</required-tag2>
    <tag3>not important info</tag3>
    <tag4>not important info</tag4>
    <first-name>John</first-name>
    <last-name>Jhonny</last-name>
    <licenses>
        <license>
            <number>840790</number>
            <state xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">TX</state>
            <field xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">Health</field>
        </license>
        <license>
            <number>840790</number>
            <state xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">NY</state>
            <field xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">Health</field>
        </license>
        <license>
            <number>840790</number>
            <state xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">CA</state>
            <field xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">Health</field>
        </license>
    </licenses>
    <appointments>
        <appointment-info>
            <code>5124</code>
            <number>14920329324</number>
            <licensed-states>
                <state>TX</state>
                <state>NY</state>
            </licensed-states>
        </appointment-info>
    </appointments>
</Person>
</People>

What I want to basically do is that, if a Person is licensed in a state for example TX. And has appointment information in that state for example TX, filter that from licenses. If that is the only license information then filter the person.

And the new xml should contain information of required tags. And only Licenses which didn't match with licenses in appointment licenses state. And filtered person who matched all licenses.

<?xml version="1.0" encoding="UTF-8"?>
<People>
<Person>
    <required-tag1>some-information</required-tag1>
    <required-tag2>some-information</required-tag2>
    <first-name>Mike</first-name>
    <last-name>Hewitt</last-name>
    <licenses>
        <license>
            <number>938387</number>
            <state xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">IL</state>
            <field xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">Health</field>
        </license>
    </licenses>
</Person>
<Person>
    <required-tag1>some-information</required-tag1>
    <required-tag2>some-information</required-tag2>
    <first-name>John</first-name>
    <last-name>Jhonny</last-name>
    <licenses>
        <license>
            <number>1762539</number>
            <state xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">NY</state>
            <field xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">Health</field>
        </license>
    </licenses>
</Person>
<Person>
    <required-tag1>some-information</required-tag1>
    <required-tag2>some-information</required-tag2>
    <first-name>John</first-name>
    <last-name>Jhonny</last-name>
    <licenses>
        <license>
            <number>840790</number>
            <state xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">CA</state>
            <field xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">Health</field>
        </license>
    </licenses>
</Person>
</People>

How to write an XSLT to filter this information. I am using XSLT Version 1.0

Currently I am able to apply this XSLT to get the required tags for transformation. But I don't know how to filter for Licenses States:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output encoding="UTF-8" indent="yes" method="xml"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/People">
  <People>
  <xsl:apply-templates select="Person"/>
  </People>
 </xsl:template>
 <xsl:template match="Person">
   <Person>
  <xsl:copy-of select="required-tag1"/>
  <xsl:copy-of select="required-tag2"/>
  <xsl:copy-of select="first-name"/>
  <xsl:copy-of select="last-name"/>
</Person>
</xsl:template>
</xsl:stylesheet>

标签: xml xslt
1条回答
放荡不羁爱自由
2楼-- · 2019-08-07 07:03

Like most XSLTs, start with an identity transform and then override it.

You can filter out the licenses by only overriding a license whose state matches a state in a licensed-states.

XML Input

<People>
    <Person>
        <required-tag1>some-information</required-tag1>
        <required-tag2>some-information</required-tag2>
        <tag3>not important info</tag3>
        <tag4>not important info</tag4>
        <first-name>Mike</first-name>
        <last-name>Hewitt</last-name>
        <licenses>
            <license>
                <number>938387</number>
                <state xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">TX</state>
                <field xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">Health</field>
            </license>
            <license>
                <number>938387</number>
                <state xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">IL</state>
                <field xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">Health</field>
            </license>
        </licenses>
        <appointments>
            <appointment-info>
                <code>5124</code>
                <number>14920329324</number>
                <licensed-states>
                    <state>TX</state>
                </licensed-states>
            </appointment-info>
        </appointments>
    </Person>
    <Person>
        <required-tag1>some-information</required-tag1>
        <required-tag2>some-information</required-tag2>
        <tag3>not important info</tag3>
        <tag4>not important info</tag4>
        <first-name>John</first-name>
        <last-name>Jhonny</last-name>
        <licenses>
            <license>
                <number>1762539</number>
                <state xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">TX</state>
                <field xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">Health</field>
            </license>
            <license>
                <number>1762539</number>
                <state xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">NY</state>
                <field xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">Health</field>
            </license>
        </licenses>
        <appointments>
            <appointment-info>
                <code>5124</code>
                <number>14920329324</number>
                <licensed-states>
                    <state>TX</state>
                </licensed-states>
            </appointment-info>
        </appointments>
    </Person>
    <Person>
        <required-tag1>some-information</required-tag1>
        <required-tag2>some-information</required-tag2>
        <tag3>not important info</tag3>
        <tag4>not important info</tag4>
        <first-name>Mike</first-name>
        <last-name>Hewitt</last-name>
        <licenses>
            <license>
                <number>17294083</number>
                <state xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">IL</state>
                <field xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">Health</field>
            </license>
        </licenses>
        <appointments>
            <appointment-info>
                <code>5124</code>
                <number>14920329324</number>
                <licensed-states>
                    <state>IL</state>
                </licensed-states>
            </appointment-info>
        </appointments>
    </Person>
    <Person>
        <required-tag1>some-information</required-tag1>
        <required-tag2>some-information</required-tag2>
        <tag3>not important info</tag3>
        <tag4>not important info</tag4>
        <first-name>John</first-name>
        <last-name>Jhonny</last-name>
        <licenses>
            <license>
                <number>840790</number>
                <state xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">TX</state>
                <field xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">Health</field>
            </license>
            <license>
                <number>840790</number>
                <state xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">NY</state>
                <field xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">Health</field>
            </license>
            <license>
                <number>840790</number>
                <state xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">CA</state>
                <field xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">Health</field>
            </license>
        </licenses>
        <appointments>
            <appointment-info>
                <code>5124</code>
                <number>14920329324</number>
                <licensed-states>
                    <state>TX</state>
                    <state>NY</state>
                </licensed-states>
            </appointment-info>
        </appointments>
    </Person>
</People>

XSLT 1.0

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output indent="yes"/>
    <xsl:strip-space elements="*"/>

    <!--Identity transform (aka identity template). This will match
    and copy attributes and nodes (element, text, comment and
    processing-instruction) without changing them. Unless a more
    specific template matches, everything will get handled by this
    template.-->
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

    <!--This template will match all "appointments", "tag3", "tag4" element nodes.
    It will also match "license" element nodes that have a child "state"
    element whose value matches a "state" element node that is a child of 
    "licensed-states".
    It will also match the "Person" element node if the number of
    "state" elements that don't have a corresponding "licensed-state"
    is equal to zero. ("filtered person who matched all licenses"
    requirement.)
    Instead of writing 4 individual xsl:templates, I used
    the union "|" operator in the "match" attribute. Since the "xsl:template" is 
    empty, nothing is output or processed further.-->
    <xsl:template match="appointments|license[state=../..//licensed-states/state]|tag3|
    tag4|Person[count(licenses/license[not(state=../..//licensed-states/state)])=0]"/>

</xsl:stylesheet>

XML Output

<People>
   <Person>
      <required-tag1>some-information</required-tag1>
      <required-tag2>some-information</required-tag2>
      <first-name>Mike</first-name>
      <last-name>Hewitt</last-name>
      <licenses>
         <license>
            <number>938387</number>
            <state xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">IL</state>
            <field xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">Health</field>
         </license>
      </licenses>
   </Person>
   <Person>
      <required-tag1>some-information</required-tag1>
      <required-tag2>some-information</required-tag2>
      <first-name>John</first-name>
      <last-name>Jhonny</last-name>
      <licenses>
         <license>
            <number>1762539</number>
            <state xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">NY</state>
            <field xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">Health</field>
         </license>
      </licenses>
   </Person>
   <Person>
      <required-tag1>some-information</required-tag1>
      <required-tag2>some-information</required-tag2>
      <first-name>John</first-name>
      <last-name>Jhonny</last-name>
      <licenses>
         <license>
            <number>840790</number>
            <state xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">CA</state>
            <field xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">Health</field>
         </license>
      </licenses>
   </Person>
</People>

If you end up filtering out more nodes than you keep, you can switch it up and do an xsl:apply-templates to handle more of the filtering...

XSLT 1.0 (same output as above)

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output indent="yes"/>
    <xsl:strip-space elements="*"/>

    <!--Identity transform (aka identity template). This will match
    and copy attributes and nodes (element, text, comment and
    processing-instruction) without changing them. Unless a more
    specific template matches, everything will get handled by this
    template.-->    
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

    <!--This template will match the "Person" element node. The "xsl:copy"
    creates the new "Person" element. The "xsl:apply-templates" tells
    the processor to apply templates to any attributes (of Person) or
    elements listed in the "select". (Other elements will not be 
    processed.) I used the union operator in the "select" so I wouldn't
    have to write multiple "xsl:apply-templates".-->
    <xsl:template match="Person">
        <xsl:copy>
            <xsl:apply-templates select="@*|first-name|last-name|
                required-tag1|required-tag2|licenses"/>
        </xsl:copy>
    </xsl:template>

    <!--This template will match any "license" element nodes that have a child 
    "state" element whose value matches a "state" element node that is a 
    child of "licensed-states". 
    This template will also match the "Person" element node if the number of
    "state" elements that don't have a corresponding "licensed-state"
    is equal to zero. ("filtered person who matched all licenses"
    requirement.)
    Since the "xsl:template" is empty, nothing 
    is output or processed further.-->
    <xsl:template match="license[state=../..//licensed-states/state]|
    Person[count(licenses/license[not(state=../..//licensed-states/state)])=0]"/>

</xsl:stylesheet>
查看更多
登录 后发表回答