Getting attribute names and doing some manipulations in xslt - xslt

I have to get the attribute names and do some manipulations based on the its name in XSLT.
Source:
<group xlink:type="simple" xlink:href="XXX" xlink:title="sectionHeader_1" xmlns:xlink="http://www.w3.org/1999/xlink"></group>
<group xlink:type="simple" xlink:href="YYY" xlink:title="BodyParagraph_1" xmlns:xlink="http://www.w3.org/1999/xlink"></group>
<group xlink:type="simple" xlink:href="ZZZ" xlink:title="sectionHeader_2" xmlns:xlink="http://www.w3.org/1999/xlink"></group>
<group xlink:type="simple" xlink:href="AAA" xlink:title="sectionHeader_3" xmlns:xlink="http://www.w3.org/1999/xlink"></group>
<group xlink:type="simple" xlink:href="BBB" xlink:title="BodyParagraph_2" xmlns:xlink="http://www.w3.org/1999/xlink"></group>
<group xlink:type="simple" xlink:href="BBB" xlink:title="ConditionalText_2" xmlns:xlink="http://www.w3.org/1999/xlink"></group>
I have to get the attribute xlink:title attribute in it and check for the following:
when the attribute xlink:title contains string sectionHeader , I need to do some manipulations.
when the attribute xlink:title contains string BodyParagraph, I need to some manipulations.
when the attribute xlink:title contains string ConditionalText, I need to some manipulations.
Can any one explain how it can be done?

It is in the spirit of XSLT to use templates and pattern matching so that explicit conditional instructions are minimized or eliminated altogether.
Here is how this can be done:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xlink="http://www.w3.org/1999/xlink">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="group">
<xsl:apply-templates select="#xlink:title"/>
</xsl:template>
<xsl:template match="#xlink:title[contains(., 'sectionHeader')]">
Found #xlink:title containing "sectionHeader"
</xsl:template>
<xsl:template match="#xlink:title[contains(., 'BodyParagraph')]">
Found #xlink:title containing "BodyParagraph"
</xsl:template>
<xsl:template match="#xlink:title[contains(., 'ConditionalText')]">
Found #xlink:title containing "ConditionalText"
</xsl:template>
</xsl:stylesheet>
When this transformation is applied on the provided XML fragment (converted to a well-formed XML document):
<t>
<group xlink:type="simple" xlink:href="XXX" xlink:title="sectionHeader_1" xmlns:xlink="http://www.w3.org/1999/xlink"></group>
<group xlink:type="simple" xlink:href="YYY" xlink:title="BodyParagraph_1" xmlns:xlink="http://www.w3.org/1999/xlink"></group>
<group xlink:type="simple" xlink:href="ZZZ" xlink:title="sectionHeader_2" xmlns:xlink="http://www.w3.org/1999/xlink"></group>
<group xlink:type="simple" xlink:href="AAA" xlink:title="sectionHeader_3" xmlns:xlink="http://www.w3.org/1999/xlink"></group>
<group xlink:type="simple" xlink:href="BBB" xlink:title="BodyParagraph_2" xmlns:xlink="http://www.w3.org/1999/xlink"></group>
<group xlink:type="simple" xlink:href="BBB" xlink:title="ConditionalText_2" xmlns:xlink="http://www.w3.org/1999/xlink"></group>
</t>
the wanted result (something done in each case) is produced:
Found #xlink:title containing "sectionHeader"
Found #xlink:title containing "BodyParagraph"
Found #xlink:title containing "sectionHeader"
Found #xlink:title containing "sectionHeader"
Found #xlink:title containing "BodyParagraph"
Found #xlink:title containing "ConditionalText"
Do note: You may consider using the starts-with() function rather than contains() .

Since you can't modify parts of an existing XML file with XSLT, you have to copy everything and change those parts that should be different. Thus, I suggest to write a template that copies each node by default. Then you can add specialized templates for the group elements that meet your conditions, e.g. something like this:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xlink="http://www.w3.org/1999/xlink">
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="group[contains(#xlink:title,'sectionHeader')]">
<group>
<xsl:copy-of select="#*"/>
<!-- modifications here -->
</group>
</xsl:template>
<xsl:template match="group[contains(#xlink:title,'BodyParagraph')]">
<group>
<xsl:copy-of select="#*"/>
<!-- modifications here -->
</group>
</xsl:template>
<xsl:template match="group[contains(#xlink:title,'ConditionalText')]">
<group>
<xsl:copy-of select="#*"/>
<!-- modifications here -->
</group>
</xsl:template>
</xsl:stylesheet>
If you want to change the attribute values too, just replace the xsl:copy-of statements with the desired modifications.

Your source XML (some modifications done):
<?xml version="1.0"?>
<root>
<group id="x1" xlink:type="simple" xlink:href="XXX" xlink:title="sectionHeader_1" xmlns:xlink="http://www.w3.org/1999/xlink"></group>
<group id="x2" xlink:type="simple" xlink:href="YYY" xlink:title="BodyParagraph_1" xmlns:xlink="http://www.w3.org/1999/xlink"></group>
<group id="x3" xlink:type="simple" xlink:href="ZZZ" xlink:title="sectionHeader_2" xmlns:xlink="http://www.w3.org/1999/xlink"></group>
<group id="x4" xlink:type="simple" xlink:href="AAA" xlink:title="sectionHeader_3" xmlns:xlink="http://www.w3.org/1999/xlink"></group>
<group id="x5" xlink:type="simple" xlink:href="BBB" xlink:title="BodyParagraph_2" xmlns:xlink="http://www.w3.org/1999/xlink"></group>
<group id="x6" xlink:type="simple" xlink:href="BBB" xlink:title="ConditionalText_2" xmlns:xlink="http://www.w3.org/1999/xlink"></group>
<group id="x7" xlink:type="simple" xlink:href="BBB" xlink:title="some_other_2" xmlns:xlink="http://www.w3.org/1999/xlink"></group>
</root>
XSL Document:
<?xml version='1.0'?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xlink="http://www.w3.org/1999/xlink">
<xsl:template match="/">
<elements>
<xsl:apply-templates/>
</elements>
</xsl:template>
<xsl:template match="//group[(contains(#xlink:title,'sectionHeader') or contains(#xlink:title,'BodyParagraph') or contains(#xlink:title,'ConditionalText'))]">
<xsl:element name="element">
<xsl:attribute name="id"><xsl:value-of select="#id"/></xsl:attribute>
<xsl:attribute name="type"><xsl:value-of select="#xlink:type"/></xsl:attribute>
<xsl:attribute name="href"><xsl:value-of select="#xlink:href"/></xsl:attribute>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
And the result:
<?xml version='1.0' ?>
<elements xmlns:xlink="http://www.w3.org/1999/xlink">
<element id="x1" type="simple" href="XXX"/>
<element id="x2" type="simple" href="YYY"/>
<element id="x3" type="simple" href="ZZZ"/>
<element id="x4" type="simple" href="AAA"/>
<element id="x5" type="simple" href="BBB"/>
<element id="x6" type="simple" href="BBB"/>
</elements>

Related

Read xml file to capture the values from <value> tags

We have a requirement to read the xml file and capture the EmployeeName and EmailId values from tags to create the output as xml file.
The first tag always represents EmployeeName and 5th tag always represents EmailId.
Need to capture the values present in the row/value....
The input xml file as follows:
<?xml version="1.0" encoding="utf-8"?>
<dataset xmlns="http://developer.net.com/schemas/xmldata/1/" xmlns:xs="http://www.w3.org/2001/XMLSchema-instance">
<!--
<dataset
xmlns="http://developer.net.com/schemas/xmldata/1/"
xmlns:xs="http://www.w3.org/2001/XMLSchema-instance"
xs:schemaLocation="http://developer.net.com/schemas/xmldata/1/ xmldata.xsd"
>
-->
<metadata>
<item length="20" type="xs:string" name="EmployeeName"/>
<item length="4" type="xs:string" name="Full/Part Time Code"/>
<item type="xs:dateTime" name="Hire Date"/>
<item type="xs:dateTime" name="Termination Date"/>
<item length="30" type="xs:string" name="EmailID"/>
<item length="30" type="xs:string" name="State"/>
</metadata>
<data>
<row>
<value>JOSEPH</value>
<value>F</value>
<value>1979-04-19T00:00:00</value>
<value>2007-08-27T00:00:00</value>
<value>joseph.Tim#gmail.com</value>
<value>TX</value>
</row>
<row>
<value>NANDY</value>
<value>F</value>
<value>1979-04-19T00:00:00</value>
<value>2007-08-27T00:00:00</value>
<value>Nandy123#gmailcom</value>
<value>PA</value>
</row>
</data>
</dataset>
The Expected Ouput as below:
<?xml version="1.0" encoding="UTF-8"?>
<ns0:EMPLOYEEDETAILS xmlns:ns0="http://net.com/EmployeeDetails">
<Records>
<EmployeeName>JOSEPH</EmployeeName>
<EmailId>joseph.Tim#gmail.com</EmailId>
</Records>
<Records>
<EmployeeName>NANDY</EmployeeName>
<EmailId>Nandy123#gmailcom</EmailId>
</Records>
</ns0:EMPLOYEEDETAILS>
Thanks,
Ravi
Please try the XSLT below. You need to make additional changes for matching namespaces according to the input XML and adding the root node <EMPLOYEEDETAILS> in the output.
EDIT: XSLT solution updated to handle the namespace issue. Root node <ns0:EMPLOYEEDETAILS> included in the solution.
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ns0="http://developer.net.com/schemas/xmldata/1/">
<xsl:output method="xml" indent="yes" />
<xsl:strip-space elements="*"/>
<xsl:param name="param-name" select="1" />
<xsl:param name="param-email" select="5" />
<xsl:template match="/">
<ns0:EMPLOYEEDETAILS>
<xsl:for-each select="//ns0:data/ns0:row">
<Records>
<xsl:for-each select="ns0:value">
<xsl:choose>
<xsl:when test="position() = $param-name">
<EmployeeName>
<xsl:value-of select="." />
</EmployeeName>
</xsl:when>
<xsl:when test="position() = $param-email">
<EmailId>
<xsl:value-of select="." />
</EmailId>
</xsl:when>
</xsl:choose>
</xsl:for-each>
</Records>
</xsl:for-each>
</ns0:EMPLOYEEDETAILS>
</xsl:template>
</xsl:stylesheet>
Output
<ns0:EMPLOYEEDETAILS xmlns:ns0="http://developer.net.com/schemas/xmldata/1/">
<Records>
<EmployeeName>JOSEPH</EmployeeName>
<EmailId>joseph.Tim#gmail.com</EmailId>
</Records>
<Records>
<EmployeeName>NANDY</EmployeeName>
<EmailId>Nandy123#gmailcom</EmailId>
</Records>
</ns0:EMPLOYEEDETAILS>

XSLT code to pass a value in output XML based on a condition in input XML

Input XML:
<?xml version="1.0" encoding="UTF-8"?>
<DATA>
<RECORDS>
<Group>
<Name>12345</Name>
<Grp>MANAGER</Grp>
<FName>Alex</FName>
<LName>Johnson</LName>
<String1>abcd</String1>
/Group>
<Group>
<Name>67891</Name>
<Grp>PROJECT MANAGER</Grp>
<FName>JAMES</FName>
<LName>HARPER</LName>
<String1></String1>
</Group> </RECORDS> <LOGIN>
<User>
<Name>12345</UserName>
<Last>14/02/2013</Last>
</User>
<User>
<Name>67891</Name>
<Last>14/01/2013/Last>
</User> </LOGIN> </DATA>
Requirement:
In output XML
If String1 has a value then Type tag should have value as "axbx" and
if String1 is blank then Type tag should have value as "dydy"
<?xml version="1.0" encoding="UTF-8"?>
<DATA>
<RECORDS>
<Group>
<Name>12345</Name>
<Grp>MANAGER</Grp>
<FName>Alex</FName>
<LName>Johnson</LName>
<Type>axbx</Type>
</Group>
<Group>
<Name>67891</Name>
<Grp>PROJECT MANAGER</Grp>
<FName>JAMES</FName>
<LName>HARPER</LName>
<Type>dydy</Type>
</Group> </RECORDS> </DATA>
Please suggest.
I can't edit your question so I copy the corrected XML:
<?xml version="1.0" encoding="UTF-8"?>
<DATA>
<RECORDS>
<Group>
<Name>12345</Name>
<Grp>MANAGER</Grp>
<FName>Alex</FName>
<LName>Johnson</LName>
<String1>abcd</String1>
</Group>
<Group>
<Name>67891</Name>
<Grp>PROJECT MANAGER</Grp>
<FName>JAMES</FName>
<LName>HARPER</LName>
<String1></String1>
</Group>
</RECORDS>
<LOGIN>
<User>
<Name>12345</Name>
<Last>14/02/2013</Last>
</User>
<User>
<Name>67891</Name>
<Last>14/01/2013</Last>
</User>
</LOGIN>
</DATA>
and the XSL
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" encoding="utf-8" indent="yes"/>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="String1">
<Type>
<xsl:choose>
<xsl:when test="string-length(.) > 0">axbx</xsl:when>
<xsl:otherwise>dydy</xsl:otherwise>
</xsl:choose>
</Type>
</xsl:template>
</xsl:stylesheet>
I'm not very experienced so there might be a better way.

Not able to group similar records in XSLT

I am trying to group all similar records based on language. But I am not able to group in XSLT.
I am using XSL KEY function group the record in XSLT. I am trying loop and add each group records to one group.
I have the following input xml.
<root>
<element name="David" language="German"></element>
<element name="Sarah" language="German"></element>
<element name="Isaac" language="English"></element>
<element name="Abraham" language="German"></element>
<element name="Jackson" language="English"></element>
<element name="Deweher" language="English"></element>
<element name="Jonathan" language="Hindi"></element>
<element name="Mike" language="Hindi"></element>
</root>
XSLT:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs"
version="1.0">
<xsl:key name="lang" match="element" use="#language"></xsl:key>
<xsl:template match="/">
<root>
<xsl:for-each select="key('lang',//element/#language)">
<Group>
<xsl:attribute name="name" select=".//#language"></xsl:attribute>
<member><xsl:value-of select=".//#name"/></member>
</Group>
</xsl:for-each>
</root>
</xsl:template>
</xsl:stylesheet>
Expected Output :
<root>
<Group name="German">
<member>David</member>
<member>Sarah</member>
<member>Abraham</member>
</Group>
<Group name="English">
<member>Isaac</member>
<member>Jackson</member>
<member>Deweher</member>
</Group>
<Group name="Hindi">
<member>Jonathan</member>
<member>Mike</member>
</Group>
</root>
Actual Output :
<root>
<Group name="German">
<member>David</member>
</Group>
<Group name="German">
<member>Sarah</member>
</Group>
<Group name="English">
<member>Isaac</member>
</Group>
<Group name="German">
<member>Abraham</member>
</Group>
<Group name="English">
<member>Jackson</member>
</Group>
<Group name="English">
<member>Deweher</member>
</Group>
<Group name="Hindi">
<member>Jonathan</member>
</Group>
<Group name="Hindi">
<member>Mike</member>
</Group>
</root>
I am getting each records separately.
Can someone please let me know what went wrong in the XSL. Thanks :)
I made some changes in your stylesheet. This should achieve the result you expect:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output indent="yes"/>
<xsl:key name="lang" match="element" use="#language"></xsl:key>
<xsl:template match="root">
<xsl:copy>
<xsl:for-each select="element[count(. | key('lang', #language)[1]) = 1]">
<Group name="{#language}">
<xsl:for-each select="key('lang', #language)">
<member><xsl:value-of select="#name"/></member>
</xsl:for-each>
</Group>
</xsl:for-each>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
The first loop selects each unique language (a node-set of size 3), and creates a context for the inner loop. The inner loop iterates through each element and selects only the ones that have the same language.
Muenchian grouping may seem hard to grasp, but you can always apply the template shown in this tutorial and not have to think much. I simply applied that template to your example.
UPDATE: Here is a solution without using for-each loops:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output indent="yes"/>
<xsl:key name="lang" match="element" use="#language"></xsl:key>
<xsl:template match="root">
<xsl:copy>
<xsl:apply-templates select="element[generate-id(.) = generate-id(key('lang', #language)[1])]"/>
</xsl:copy>
</xsl:template>
<xsl:template match="element">
<Group name="{#language}">
<xsl:apply-templates select="key('lang', #language)" mode="member"/>
</Group>
</xsl:template>
<xsl:template match="element" mode="member">
<member><xsl:value-of select="#name"/></member>
</xsl:template>
</xsl:stylesheet>

Merging pairs of nodes based on attribute, new to template matching

Say I have the following XML:
<root>
<tokens>
<token ID="t1">blah</token>
<token ID="t2">blabla</token>
<token ID="t3">shovel</token>
</tokens>
<relatedStuff>
<group gID="s1">
<references tokID="t1"/>
<references tokID="t2"/>
</group>
<group gID="s2">
<references tokID="t3"/>
</group>
</relatedStuff>
</root>
Now, considering that a for-each loop for every token would be pretty inefficient and a bad idea, how would one go about using template matching, to transform this xml into the following?
<s id="everything_merged">
<tok id="t1" gID="s1" >blah</tok>
<tok id="t2" gID="s1" >blabla</tok>
<tok id="t3" gID="s2" >shovel</tok>
</s>
All I want from <s> is the "gID", the gID corresponding to the token in the <tokens>.
<xsl:for-each select="b:root/a:tokens/a:token">
<!-- and here some template matching -->
<xsl:attribute name="gID">
<xsl:value-of select="--correspondingNode's--#gID"/>
</xsl:attribute>
</xsl:for-each>
I'm pretty fuzzy on this sort of thing, so thank you very much for any help!
The following stylesheet:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<s id="everything_merged">
<xsl:apply-templates select="/root/tokens/token" />
</s>
</xsl:template>
<xsl:template match="token">
<tok id="{#ID}" gID="{/root/relatedStuff/group[
references[#tokID=current()/#ID]]/#gID}">
<xsl:apply-templates />
</tok>
</xsl:template>
</xsl:stylesheet>
Applied to this input (corrected for well-formedness):
<root>
<tokens>
<token ID="t1">blah</token>
<token ID="t2">blabla</token>
<token ID="t3">shovel</token>
</tokens>
<relatedStuff>
<group gID="s1">
<references tokID="t1" />
<references tokID="t2" />
</group>
<group gID="s2">
<references tokID="t3" />
</group>
</relatedStuff>
</root>
Produces:
<s id="everything_merged">
<tok id="t1" gID="s1">blah</tok>
<tok id="t2" gID="s1">blabla</tok>
<tok id="t3" gID="s2">shovel</tok>
</s>
A solution using keys and pure "push-style:
<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:key name="kgIDfromTokId" match="#gID"
use="../*/#tokID"/>
<xsl:template match="tokens">
<s id="everything_merged">
<xsl:apply-templates/>
</s>
</xsl:template>
<xsl:template match="token">
<tok id="{#ID}" gID="{key('kgIDfromTokId', #ID)}">
<xsl:apply-templates/>
</tok>
</xsl:template>
</xsl:stylesheet>
when applied on the provided XML document:
<root>
<tokens>
<token ID="t1">blah</token>
<token ID="t2">blabla</token>
<token ID="t3">shovel</token>
</tokens>
<relatedStuff>
<group gID="s1">
<references tokID="t1" />
<references tokID="t2" />
</group>
<group gID="s2">
<references tokID="t3" />
</group>
</relatedStuff>
</root>
the wanted, correct result is produced:
<s id="everything_merged">
<tok id="t1" gID="s1">blah</tok>
<tok id="t2" gID="s1">blabla</tok>
<tok id="t3" gID="s2">shovel</tok>
</s>

Using xslt, transform one xml document based upon the contents of a second xml document

I have one set of documents that implicitly define the allowed fields for a second set of objects that have to be transformed into a third set of documents (
which "rules" document to use depends upon the content of the file being transformed) e.g.
<!-- One example rules document -->
<document object="obj1_rules">
<field name="A"/>
<field name="B"/>
<field name="C"/>
</document>
<!-- Document to be tranformed based upon obj1_rules-->
<document object="obj1">
<field name="A"/>
<field name="B"/>
<field name="C"/>
<field name="D"/>
<field name="E"/>
</document>
<!-- Desired result-->
<document object="obj1">
<newfield name="A"/>
<newfield name="B"/>
<newfield name="C"/>
</document>
Is it possible to do this transformation using xslt?
I see that "There is no way in XSLT of constructing XPath expressions (e.g. variable references) at run-time." So I am out of luck, or I am just looking at this problem incorrectly? Thanks!
Here is a simple solution:
This transformation:
<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:variable name="vrtfRules">
<document object="obj1_rules">
<field name="A"/>
<field name="B"/>
<field name="C"/>
</document>
</xsl:variable>
<!-- -->
<xsl:variable name="vRules" select=
"document('')/*/xsl:variable
[#name = 'vrtfRules']
/*
"/>
<!-- -->
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<!-- -->
<xsl:template match="field">
<xsl:if test="#name = $vRules/*/#name">
<newfield>
<xsl:apply-templates select="node()|#*"/>
</newfield>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
when applied on the originaly-provided source XML document:
<document object="obj1">
<field name="A"/>
<field name="B"/>
<field name="C"/>
<field name="D"/>
<field name="E"/>
</document>
produces the desired result:
<document object="obj1">
<newfield name="A"/>
<newfield name="B"/>
<newfield name="C"/>
</document>
Note that the "rules document" is within the stylesheet just for compactness. When it is a separate document, just the document() function used will need to be adjusted with the actual href.
Maybe I'm oversimplifying, but is there a reason why your "rules document" cannot simply be an XSLT?
Well, I can see why you'd like to have rules in a simple xml file rather than in a full-fledged xsl stylesheet but you're simply skipping a step.
You need to make a xsl stylesheet that will transform your xml rule document into a xsl stylesheet that you will then apply onto your source xml.
The trick is with namespaces and not getting confused by the mix of xsl rules applied and xsl rules generated.
<?xml version="1.0" ?>
<xsl:stylesheet
xmlns="YOUR_NAMESPACE_HERE"
xmlns:output="http://www.w3.org/1999/XSL/Transform"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="2.0">
<xsl:output
method="xml"
indent="yes"
media-type="text/xsl" />
<xsl:template match="/">
<output:stylesheet version="2.0">
<xsl:apply-templates />
</output:stylesheet>
</xsl:template>
<xsl:template match="document[#object]">
<output:template match="document[#object='{#object}']">
<output:copy>
<xsl:apply-templates />
</output:copy>
</output:template>
</xsl:template>
<xsl:template match="field[#name]">
<output:if test="field[#name='{#name}']">
<output:copy-of select="field[#name='{#name}']" />
</output:if>
</xsl:template>
</xsl:stylesheet>
I presumed you'd use the same document object attribute in the rules and in the documents themselves (this is much simpler imo).
So, you run your rules document through the stylesheet above. The result is a new xsl stylesheet that does exactly what you describe in your xml rule document. You then apply this resulting stylesheet onto your source document and you should get the result you expect.