1

I have a source XML file. and I provide a UI for users to pick the elements they want to include in the resulting XML. How the UI works is by loading the XSD file and presenting the elements in a checkbox tree. Users then can check the elements they need.

The UI works fine, but I need some advice/guidance on the back-end logic: Basically I want to "apply a filter" to the source xml, but

  1. how should I save the user's selection (in deliminator separated values or ??) and
  2. how should I apply this "filter" (maybe with XSLT)?

EDIT: The src xml structure looks like this:

<IDs>
  <id1></id1>
  <id2></id2>
  ...
</IDs>
<Traveler>
  <name></name>
  <email></email>
  ...
<Traveler>
<Segments>
  <Segment i:type="Air">
    <carrier></carrier>
    ...
  </Segment>
  <Segment i:type="Hotel">
    <supplier></supplier>
    ...
  </Segment>
</Segments>
<Notes>
...
</Notes>

EDIT2: All of these elements can be checked/unchecked to include in the resulting xml.

6
  • No, I don't have any code for the backend logic bcz I haven't decided which approach to go with. Commented Jan 10, 2012 at 14:25
  • 1
    Copy the source file, create a list or array of the xpaths for the elements that aren't selected, iterate the xpaths and remove each one, return the result. Or am I missing something here? Commented Jan 10, 2012 at 14:27
  • @9ball, thanks that will work. I'll have that as my last resort. but is there something more elegant, such as applying xslt...i'm wondering if there is a "cookie cutter" solution where I can just go "bam" and get my resulting xml w/o iteration. Commented Jan 10, 2012 at 14:30
  • 1
    If my xslt understanding and understanding of what you're trying to do is correct, you would need to build a new xslt sheet in memory based on what the user selects. While this is possible, I don't know if it would be any more elegant. Commented Jan 10, 2012 at 14:33
  • I just thought of a solution you might like: append an attribute to the selected nodes and then use xslt to filter them Commented Jan 10, 2012 at 14:36

3 Answers 3

2

If you really want to do this using XSLT, try this approach. It copies all elements and attributes that aren't matched by whatever XPath expression you add to the second template. You'll have to dynamically generate the XSLT and compile it, so it won't be particularly fast:

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

    <xsl:output method="xml" indent="yes"/>

    <xsl:template match="@* | node()">
        <xsl:copy>
            <xsl:apply-templates select="@* | node()"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="XPath for all non-selected elements"></xsl:template>
</xsl:stylesheet>
Sign up to request clarification or add additional context in comments.

2 Comments

thanks. I'll take your advice if i chose to go down the xslt path. do you know if "xml filtering as3" has anything to do with this question? I'm taking a wild guess here.
I think that refers to a way of filtering XML using ActionScript 3. You could do something similar using Linq to XML, but it might require writing more code than the XSLT approach.
1

The processing depends very much on the structure of the XML, which you haven't shown.

It can be as simple as this:

<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:param name="pWanted" select="'|A|C|'"/>

 <xsl:template match="node()|@*" name="identity">
  <xsl:copy>
   <xsl:apply-templates select="node()|@*"/>
  </xsl:copy>
 </xsl:template>

 <xsl:template match="*/*">
   <xsl:if test="contains($pWanted, concat('|',name(), '|'))">
    <xsl:call-template name="identity"/>
   </xsl:if>
 </xsl:template>
</xsl:stylesheet>

when this transformation is applied on the following XML document:

<t>
    <A>1</A>
    <B>2</B>
    <C>3</C>
</t>

the wanted, correct result is produced (only the user-specified elements A and C remain in the output):

<t>
   <A>1</A>
   <C>3</C>
</t>

2 Comments

I've included a sample of the structure.
@Lagoona:That's a good first step. Next: what are the possible user-specified selections (what is selectable from the provided XML and what is non-selectable (mandatory)) ?
1

When we created a user-friendly tool to work with our server configuration files (which are not-exactly-user-friendly XML), we opted to store the user choices (differences against the default configuration) directly as a XSL transformation.

In your case, this should work as well, but it depends on the exact structure of your XML. If your original XML is something like

<data>
  <item id="1">...</item>
  <item id="2">...</item>
  ...
</data>

You can store the selection as e.g.:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="/data">
    <data>
        <xsl:apply-templates select="item" />
    </data>
    </xsl:template>

    <xsl:template match="item[@id='1']">
    <xsl:copy-of select="."/>
    </xsl:template>
    <xsl:template match="item[@id='3']">
    <xsl:copy-of select="."/>
    </xsl:template>
    <xsl:template match="item[@id='4']">
    <xsl:copy-of select="."/>
    </xsl:template>

    <xsl:template match="node()" />
</xsl:stylesheet>

This is simple enough your tool should be able to load it back and let the user modify his choices.

1 Comment

THX. I really like this approach in saving the configuration. and good point on choosing xml as the format.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.