问题
I have this tree:
<Events>
<Properties>
<Property Descriptor=100>1378314022</Property>
<Property Descriptor=200>ABC1234</Property>
</Properties>
<Properties>
<Property Descriptor=100>1378314023</Property>
<Property Descriptor=200>ABC1234</Property>
</Properties>
<Properties>
<Property Descriptor=100>1378314024</Property>
<Property Descriptor=200>ABC1234</Property>
</Properties>
<Properties>
<Property Descriptor=100>1378314022</Property>
<Property Descriptor=200>123456</Property>
</Properties>
<Properties>
<Property Descriptor=100>1378314023</Property>
<Property Descriptor=200>123456</Property>
</Properties>
<Properties>
<Property Descriptor=100>1378314024</Property>
<Property Descriptor=200>123456</Property>
</Properties>
</Events>
I'm iterating at this level: Events/Properties
How can I have only the FIRST and LAST occurrence of each Property Descriptor = 200
and its respective Property Descriptor = 100
?
I've tried so far:
- Iteration:
Events/Properties
- Select:
Property[@Descriptor=200])[last()] or Property[@Descriptor=200])[first()]
but with no success.
OUTPUT should look like this [I'm showing it in HTML, iterating in the ROW level]:
P100 | P200
1378314022 | ABC1234
1378314024 | ABC1234
1378314022 | 123456
1378314024 | 123456
回答1:
In XSLT 2.0 this would be easy with for-each-group
, grouping by the 200 value and taking the first and last members of each group. But in pure XPath (not XSLT) you need to think laterally.
If the groups are always contiguous as you've shown here (i.e. all the ABC1234
entries are adjacent to one another, and all the 123456
entries are adjacent to one another) then this boils down to wanting every Properties
element P that does not have an immediately preceding and an immediately following sibling Properties
element with the same 200
value as P. I.e. you want to iterate over
Events/Properties[not(
(
Property[@Descriptor="200"] =
preceding-sibling::Properties[1]/Property[@Descriptor="200"]
) and (
Property[@Descriptor="200"] =
following-sibling::Properties[1]/Property[@Descriptor="200"]
)
)]
and then select the Property[@Descriptor="100"]
and Property[@Descriptor="200"]
from each of the resulting Properties
elements.
You've tagged your question "xpath-2.0" but this expression is also valid in XPath 1.0.
回答2:
I am not completely sure which answer you are looking for, but here I will give you two examples. One of them should probably fit your needs.
I used the following input XML:
<?xml version="1.0" encoding="UTF-8"?>
<Events>
<Properties>
<Property Descriptor="100">1378314022</Property>
<Property Descriptor="200">ABC1234</Property>
<Property Descriptor="100">MD2356</Property>
<Property Descriptor="200">25689</Property>
<Property Descriptor="100">MD75632</Property>
<Property Descriptor="200">5632</Property>
</Properties>
<Properties>
<Property Descriptor="100">1378314023</Property>
<Property Descriptor="200">ABC1234</Property>
<Property Descriptor="100">MD2356</Property>
<Property Descriptor="200">25689</Property>
<Property Descriptor="100">MD75632</Property>
<Property Descriptor="200">5632</Property>
</Properties>
<Properties>
<Property Descriptor="100">1378314024</Property>
<Property Descriptor="200">ABC1234</Property>
<Property Descriptor="100">MD2356</Property>
<Property Descriptor="200">25689</Property>
<Property Descriptor="100">MD75632</Property>
<Property Descriptor="200">5632</Property>
</Properties>
<Properties>
<Property Descriptor="100">1378314022</Property>
<Property Descriptor="200">123456</Property>
<Property Descriptor="100">MD2356</Property>
<Property Descriptor="200">25689</Property>
<Property Descriptor="100">MD75632</Property>
<Property Descriptor="200">5632</Property>
</Properties>
<Properties>
<Property Descriptor="100">1378314023</Property>
<Property Descriptor="200">123456</Property>
<Property Descriptor="100">MD2356</Property>
<Property Descriptor="200">25689</Property>
<Property Descriptor="100">MD75632</Property>
<Property Descriptor="200">5632</Property>
</Properties>
<Properties>
<Property Descriptor="100">1378314024</Property>
<Property Descriptor="200">123456</Property>
<Property Descriptor="100">MD2356</Property>
<Property Descriptor="200">25689</Property>
<Property Descriptor="100">MD75632</Property>
<Property Descriptor="200">5632</Property>
</Properties>
</Events>
When I use the next XSLT:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="Properties">
<xsl:copy>
<xsl:apply-templates select="Property[@Descriptor = '100'][1]" />
<xsl:apply-templates select="Property[@Descriptor = '100'][last()]" />
<xsl:apply-templates select="Property[@Descriptor = '200'][1]" />
<xsl:apply-templates select="Property[@Descriptor = '200'][last()]" />
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
This XSLT also has a iteration over the Properties
element, within that Properties
element it gets the first and the last occurence of each provided Descriptor
. The result would be:
<?xml version="1.0" encoding="UTF-8"?>
<Events>
<Properties>
<Property Descriptor="100">1378314022</Property>
<Property Descriptor="100">MD75632</Property>
<Property Descriptor="200">ABC1234</Property>
<Property Descriptor="200">5632</Property>
</Properties>
<Properties>
<Property Descriptor="100">1378314023</Property>
<Property Descriptor="100">MD75632</Property>
<Property Descriptor="200">ABC1234</Property>
<Property Descriptor="200">5632</Property>
</Properties>
<Properties>
<Property Descriptor="100">1378314024</Property>
<Property Descriptor="100">MD75632</Property>
<Property Descriptor="200">ABC1234</Property>
<Property Descriptor="200">5632</Property>
</Properties>
<Properties>
<Property Descriptor="100">1378314022</Property>
<Property Descriptor="100">MD75632</Property>
<Property Descriptor="200">123456</Property>
<Property Descriptor="200">5632</Property>
</Properties>
<Properties>
<Property Descriptor="100">1378314023</Property>
<Property Descriptor="100">MD75632</Property>
<Property Descriptor="200">123456</Property>
<Property Descriptor="200">5632</Property>
</Properties>
<Properties>
<Property Descriptor="100">1378314024</Property>
<Property Descriptor="100">MD75632</Property>
<Property Descriptor="200">123456</Property>
<Property Descriptor="200">5632</Property>
</Properties>
</Events>
If you want to get the last en first occurence over all the Properties
the XSLT should be slightly different:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="Events">
<xsl:copy>
<Properties>
<xsl:apply-templates select="(Properties/Property[@Descriptor = '100'])[1]" />
<xsl:apply-templates select="(Properties/Property[@Descriptor = '100'])[last()]" />
<xsl:apply-templates select="(Properties/Property[@Descriptor = '200'])[1]" />
<xsl:apply-templates select="(Properties/Property[@Descriptor = '200'])[last()]" />
</Properties>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
The result would then be:
<?xml version="1.0" encoding="UTF-8"?>
<Events>
<Properties>
<Property Descriptor="100">1378314022</Property>
<Property Descriptor="100">MD75632</Property>
<Property Descriptor="200">ABC1234</Property>
<Property Descriptor="200">5632</Property>
</Properties>
</Events>
来源:https://stackoverflow.com/questions/23060770/xpath2-0-selecting-first-and-last-occurance-of-string-with-iteration