Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Westi on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Multiple documents, context problem. 1

Status
Not open for further replies.

Crisps

Programmer
Sep 28, 2006
26
US
I have an XML document (A) which I need to transform using a stylesheet (S).

I intend to do this by loading a second XML document with structure information in it (B)

I have no control over document A, just B and S.

My problem is as follows:

I start to process with document A as the context document, then I do a for-each selecting the other document e.g. select="document(B.xml)/*/*"

Now the context document is document B. I can then read some structure information into a variable e.g. name='a_xpath' select='@xpath'.

the xpath I have just read refers to document A. I now need to select from document A using the xpath I just retrieved from B.

Is this possible?

The second issue with this is that I need to remain in the context of B as I need to iterate through several nodes and children. I also do not know the name of document A unless there is a way to get that in XSLT so cannot use document().


 
I really see no tremendous problems in this approach. You can collect nodesets into variables, and then your 'context' can be the variable itself.

It would seem that you will need to make extensive use of XPath predicates, but I really haven't done a lot of thinking obout this approach.

Tom Morrison
 
Thanks,

could you give me an example of some xpath please.

e.g. I have a variable called $context_root which selects /* from the first document. I also have a variable called $data_path with the xpath line '/root/data/field1'

How can I select the data from the xpath?

I have tried various statements similar to $context_root/$data_path and $context_root[$data_path] but with no success.

I can modify the xpath line as needed.
 
Please supply an example (reduced in complexity as much as possible) to illustrate your input documents, along with what your desired output might be.

I think you will be facing a recursive situation in which you traverse an XPath expression ($data_path in your previous post) selecting your way down the tree of which $context_root is the root node. When you get to the end of the XPath expression, you will output the value of the node.

This should be fairly easy as long as your XPath expressions remain relatively easy location paths.

So, supply an example, and perhaps we can stop guessing.

Tom Morrison
 
Document A

<root>
<data>
<field1>Cruel</field1>
<extradata>
<field1>World</field1>
<field2>Hello</field2>
</extradata>
</data>
</root>


Document B

<fields>
<field id='1' xpath='/root/data/extradata/field2'/>
<field id='22' xpath='/root/data/field1'/>
<field id='11' xpath='/root/data/extradata/field1'/>
</fields>

Result Needed

<output>
<item id='1'>Hello</item>
<item id='22'>Cruel</item>
<item id='11'>World</item>
</output>

In this case I may have a variable called $context_root with the contets of document A and a variable $data_path with /root/data/field1.

Remember I can make all the changes I need to document B and the stylesheet. Document A and the result cannot be changed.








 
I think I have just found something that will help

I can reference the document that I want to reference by doing a document('', $context_root).

Now I just need to know how to append the xpath tho this.
 
Well, actually, I don't think that is going to help, but please go ahead and explore it.

Here is what I came up with. (Interestingly, this is not totally tangential to my current line of exploration, which involves normalizing a somewhat arbitrary document, with a known structure.)

Document A is unchanged from your example. Here is a slightly modified document B:
Code:
<fields>
 <field id="1" xpath="data/extradata/field2"/>
 <field id="22" xpath="data/field1"/>
 <field id="11" xpath="data/extradata/field1"/>
</fields>

And here is the stylesheet (I have commented out some 'debug print statements' that might be useful in understanding how this works):
Code:
<xsl:stylesheet version="1.0" xmlns:xsl="[URL unfurl="true"]http://www.w3.org/1999/XSL/Transform">[/URL]
<xsl:output indent="yes"/>
<xsl:variable name="context_root" select="/*"/>

<xsl:template match="/">
<output>
    <xsl:for-each select="document('B.xml')/fields/field">
    <item>
    <xsl:attribute name="id"><xsl:value-of select="@id"/></xsl:attribute>
    <xsl:apply-templates mode="find_text_value" select="$context_root">
        <xsl:with-param name="path_expression" select="@xpath"/>
    </xsl:apply-templates>
    </item>
    </xsl:for-each>	
</output>
</xsl:template>

<xsl:template  match="*" mode="find_text_value">
    <xsl:param name="path_expression"/>[COLOR=gray]
<!-- 
    <xsl:value-of select="local-name()"/>
    <xsl:text> : </xsl:text>
    <xsl:value-of select="$path_expression"/>
    <xsl:text>
</xsl:text>
    <xsl:for-each select="*">
        <xsl:value-of select="local-name(.)"/>
        <xsl:text> is element of </xsl:text>
        <xsl:value-of select="local-name(..)"/>
        <xsl:text>
</xsl:text>
    </xsl:for-each>
 -->[/color]	
    <xsl:choose>
    <xsl:when test="contains($path_expression, '/')">[COLOR= blue]
        <!-- This is not the terminal element name -->[/color]
        <xsl:variable name="element_name" select="substring-before($path_expression, '/')"/>
        <xsl:variable name="xpath_remainder" select="substring-after($path_expression, '/')"/>
        <xsl:apply-templates mode="find_text_value" select="*[local-name()=$element_name]">
            <xsl:with-param name="path_expression" select="$xpath_remainder"/>
        </xsl:apply-templates>
    </xsl:when>
    <xsl:otherwise>[COLOR= blue]
        <!-- This is the terminal element name, so output the text node value -->[/color]
        <xsl:value-of select="*[local-name()=$path_expression]"/>
    </xsl:otherwise>
    </xsl:choose>
</xsl:template>

</xsl:stylesheet>

And here is the output:
Code:
<output>
  <item id="1">Hello</item>
  <item id="22">Cruel</item>
  <item id="11">World</item>
</output>

Hope this helps.

Tom Morrison
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top