XSLT Can't match element with specific namespa

2019-09-16 08:50发布

问题:

I have this XML source file:

<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="c:\ISO19139_rve.xsl"?>
<MD_Metadata xmlns="http://www.isotc211.org/schemas/2005/gmd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:gco="http://www.isotc211.org/schemas/2005/gco" xmlns:gml="http://www.opengis.net/gml" xmlns:xlink="http://www.w3.org/1999/xlink" xsi:schemaLocation="http://www.isotc211.org/schemas/2005/gmd/gmd.xsd">
    <identificationInfo>
        <MD_DataIdentification>    
            <extent>
                <EX_Extent>
                    <geographicElement>
                        <EX_GeographicExtent>
                            <EX_GeographicBoundingBox>
                                <westBoundLongitude>
                                    <gco:Decimal>1</gco:Decimal>
                                </westBoundLongitude>
                                <eastBoundLongitude>
                                    <gco:Decimal>2</gco:Decimal>
                                </eastBoundLongitude>
                                <southBoundLatitude>
                                    <gco:Decimal>3</gco:Decimal>
                                </southBoundLatitude>
                                <northBoundLatitude>
                                    <gco:Decimal>4</gco:Decimal>
                                </northBoundLatitude>
                            </EX_GeographicBoundingBox>
                        </EX_GeographicExtent>
                    </geographicElement>
                    <temporalElement>
                        <EX_TemporalExtent>
                            <extent>
                                <gml:TimePeriod gml:id="tp1">
                                    <gml:begin>
                                        <gml:TimeIstant gml:id="ti1">
                                            <gml:timePosition>2007-12-01</gml:timePosition>
                                        </gml:TimeIstant>
                                    </gml:begin>
                                    <gml:end>
                                        <gml:TimeIstant gml:id="ti2">
                                            <gml:timePosition>2010-01-01</gml:timePosition>
                                        </gml:TimeIstant>
                                    </gml:end>
                                </gml:TimePeriod>
                            </extent>
                        </EX_TemporalExtent>
                    </temporalElement>
                </EX_Extent>
            </extent>
        </MD_DataIdentification>
    </identificationInfo>
</MD_Metadata>

And I need to replace the block with this simple one:

...
<gml:TimePeriod gml:id="TP1">
    <gml:beginPosition>2007-12-01</gml:beginPosition>
    <gml:endPosition>2010-01-01</gml:endPosition>
</gml:TimePeriod>
...

This is my transformation:

<xsl:stylesheet
    version="2.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xlink="http://www.w3.org/1999/xlink"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:gml="http://www.opengis.net/gml/3.2"
    xmlns:gco="http://www.isotc211.org/schemas/2005/gco"
    xmlns:gmd="http://www.isotc211.org/schemas/2005/gmd"
    xmlns="http://www.isotc211.org/schemas/2005/gmd"
    >

    <xsl:strip-space elements="*"/>

    <xsl:output indent="yes" encoding="UTF-8"/>

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

    <xsl:template match="gml:TimePeriod">
        <xsl:copy>
            <xsl:apply-templates select="@*"/>
            <beginPosition>
                <xsl:value-of select="gml:begin/gml:TimeIstant/gml:timePosition"/>
            </beginPosition>
            <endPosition>
                <xsl:value-of select="gml:end/gml:TimeIstant/gml:timePosition"/>
            </endPosition>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

There's the xmlns:gml="http://www.opengis.net/gml" declaration on the top of the stylesheet but I think it's a matter of namespace. If I put a break point near the

<xsl:template match="gml:TimePeriod" exclude-result-prefixes="#all">

line, I never enter inside that code. It seems that if I need to go through <gmd:...> elements, all works fine, but when I need to reach a <gml:...> (or any other different from gmd) element, it doesn't match.

-- UPDATED on 2014-04-15 --

I forgot to specify that I also need to convert to UPPER-CASE the "tp1" attribute value of <gml:TimePeriod gml:id="tp1"> element. What do I need to change on my actual transformation?

回答1:

As Tomalak mentions in the comments, the root cause of your problem is that you have different namespace URIs mapped to the gml prefix in your input XML and in your stylesheet, so the elements in your XML and the elements that the XSLT is looking to match are not considered the same.

Regarding your addition:

I forgot to specify that I also need to convert to UPPER-CASE the "tp1" attribute value of <gml:TimePeriod gml:id="tp1"> element. What do I need to change on my actual transformation?

this should just be a matter of adding one extra template (once you've got the namespaces aligned) and using the XPath 2.0 upper-case function:

<xsl:template match="gml:TimePeriod/@gml:id">
  <xsl:attribute name="gml:id" select="upper-case(.)" />
</xsl:template>

This will affect only the ids of gml:TimePeriod elements, if you want to upper-case all the IDs then simply make it match="@gml:id" instead.