This is the mail archive of the xsl-list@mulberrytech.com mailing list .


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

RE: Identifying two tags that share some attribute names and values - XPATH 2.0 SOLUTION


[NOTE: XPath 2.0 is still in Working Draft stage, subject to change, and not
yet ready for prime time.]

While the magical expression you want cannot be expressed in XPath 1.0, it
can easily be expressed in XPath 2.0:


document('2.xml')/outsidedata/b
    [every $att in @* satisfies current()/@*
         [.=$att and node-name(.)=node-name($att)]]


The "every" expression is called a universal quantifier[1] and enables you
to test that a condition applies for *every* node in a given sequence. This
is something that could not be done in general in XPath 1.0.

The node-name() function[2] returns an "expanded QName" type that consists
of a local/URI pair that can in turn be compared with other expanded names.
This ensures that your code is robust in the face of namespace-qualified
attributes without having to write [local-name(.)=local-name($att) and
namespace-uri(.)=namespace-uri($att)]. This is a welcome shorthand indeed!

Except for the node-name() function, I'm happy to report that a stylesheet
with this expression (using name() instead) is executed as expected by Saxon
7.1. Below is the stylesheet I ran against your two files:


<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform";>

  <xsl:output method="text"/>

  <xsl:template match="/">
    <xsl:apply-templates select="/mydata/a"/>
  </xsl:template>

  <xsl:template match="/mydata/a">
    <xsl:for-each select="document('2.xml')/outsidedata/b
                             [every $att in @* satisfies current()/@*
                                    [.=$att and name(.)=name($att)]]">
      <xsl:text>[</xsl:text>
      <xsl:value-of select="."/>
      <xsl:text>]</xsl:text>
      <xsl:if test="position() != last()">
        <xsl:text>
</xsl:text>
      </xsl:if>
    </xsl:for-each>
  </xsl:template>

</xsl:stylesheet>


Invocation and output:

$ java net.sf.saxon.Transform 1.xml test.xsl
[PPP]
[QQQ]
[RRR]
$

With your (corrected) reformulation of the original problem, I believe the
expression only needs slight modification (@* trades places with
current()/@*):

document('2.xml')/outsidedata/b
    [every $att in current()/@* satisfies @*
         [.=$att and node-name(.)=node-name($att)]]

Hope you found this helpful, or at least interesting!

Evan

[1] http://www.w3.org/TR/xpath20/#id-quantified-expressions
[2] http://www.w3.org/TR/xquery-operators/#func-node-name


> -----Original Message-----
> From: owner-xsl-list@lists.mulberrytech.com
> [mailto:owner-xsl-list@lists.mulberrytech.com]On Behalf Of Zack Brown
> Sent: Saturday, May 04, 2002 11:08 AM
> To: xsl-list@lists.mulberrytech.com
> Subject: [xsl] Identifying two tags that share some attribute names and
> values
>
>
> Hi folks,
>
> I've been migrating the Kernel Traffic web site
> (http://kt.zork.net) over to an
> XML/XSLT-based production system. So far it looks like something
> I should have
> done years ago. Compilation time (compared with my old home-grown
> processor)
> has dropped from hours to minutes, and the flexibility to add new features
> is just amazing.
>
> However, there are still a few things that are giving me
> problems. One such
> boils down to trying to identify a set of tags that share attributes with
> a target tag. So for instance I have two files, 1.xml and 2.xml:
>
> ----------------------------- 1.xml ---------------------------------
> <?xml version="1.0" ?>
>
> <mydata>
> <a x="1" y="2" z="3">test</a>
> </mydata>
> ---------------------------------------------------------------------
>
> ----------------------------- 2.xml ---------------------------------
> <?xml version="1.0" ?>
>
> <outsidedata>
> <b x="1" y="2">PPP</b>
> <b y="2" z="3">QQQ</b>
> <b z="3">RRR</b>
> <b x="9" y="8" z="7">SSS</b>
> <b m="2" z="3">TTT</b>
> </outsidedata>
> ---------------------------------------------------------------------
>
> Basically, 1.xml represents a newsletter file, and 2.xml is an
> automatically
> generated file that contains cross-reference information. The <a> tag in
> 1.xml is a cross-reference request that needs to be resolved using data
> available in 2.xml.
>
> processing is done on 1.xml, which reads in 2.xml via the document()
> function. The XSLT code analyzes 2.xml and looks for all <b> tags whose
> attributes precisely match attributes found in the target <a>
> tag. Note that
> not all of <a>'s attributes must be present in a matching <b>, but all of
> <b>'s attributes must be present in <a> and must share the same values as
> the corresponding attributes in <a>. Also note that <a>'s
> attributes are not
> necessarily "x", "y", and "z", but could be anything. The XSLT code should
> not make assumptions about their names or how many there may be.
>
> So in the above example files, <a> contains attributes "x", "y", and "z",
> which each have the values "1", "2", and "3" respectively.
> Looking at 2.xml,
> you can see that the first, second and third <b> tags are
> successful matches,
> while the fourth and fifth are not.
>
> What I need is a recipe like the following (except that works ;-):
>
> ----------------- XSLT code for processing a.xml --------------------
> <!-- Resolve kcrefs -->
> <xsl:template match="mydata/a">
> <xsl:for-each select="document('2.xml')/outsidedata/b">
> [<xsl:value-of select="."/>]
> </xsl:for-each>
> </xsl:template>
> ---------------------------------------------------------------------
>
> in which the output would look something like this:
>
> ----------------------- Desired output ------------------------------
> [PPP]
> [QQQ]
> [RRR]
> ---------------------------------------------------------------------
>
> I hope I've described this well enough. I don't even know if it's possible
> to do what I'm asking for, though it seems like it should be. Any
> help would
> be greatly appreciated.
>
> Many thanks,
> Zack
>
> --
> Zack Brown
>
>
>  XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list
>
>


 XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]