XSLT 将命名空间前缀添加到元素最佳实践
Posted
技术标签:
【中文标题】XSLT 将命名空间前缀添加到元素最佳实践【英文标题】:XSLT Add namespace prefix to element best practice 【发布时间】:2014-04-17 08:33:00 【问题描述】:出于验证目的,我需要为我的转换结果文件的每个元素添加命名空间前缀。 我在下面写了转换,但我认为这不是做我想做的最好的方法,而且无论如何它不能 100% 工作......
在我的源文件中有没有前缀的元素,我需要添加默认命名空间的前缀gmd
。但也有一些其他的元素已经指定了前缀,因为它们引用了其他命名空间,例如gco
和gml
,这些必须被维护。
在极少数情况下,我的输入文件可能已经设置了所有命名空间前缀。所以我只想继续其余的转换(为简单起见,我在这里只包含了一个其他模板)而不添加任何内容。
我的转换有效,但是:
-
在其余的转换中,我需要操作一些元素来更改子元素的顺序、名称等...以及与另一个模板匹配的那些元素,似乎与标识模板不匹配,所以我得到它们没有前缀。
我想知道如何改进我的代码。
源文件:
<?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">
<fileIdentifier>
<gco:CharacterString>b0101011_Vincolo</gco:CharacterString>
</fileIdentifier>
<language>
<gco:CharacterString>IT</gco:CharacterString>
</language>
<contact>
<CI_ResponsibleParty>
<organizationName>
<gco:CharacterString>Comune di Conselve (capofila PATI)</gco:CharacterString>
</organizationName>
<role>
<CI_RoleCode codeList="./resource/codeList.xml#CI_RoleCode" codeListValue="Autore">Autore</CI_RoleCode>
</role>
<contactInfo>
<CI_Contact>
<onlineResource>
<CI_OnlineResource>
<linkage>
<URL>http://www.comune.conselve.it</URL>
</linkage>
</CI_OnlineResource>
</onlineResource>
<phone>
<CI_Telephone>
<voice>
<gco:CharacterString>0499596511</gco:CharacterString>
</voice>
</CI_Telephone>
</phone>
</CI_Contact>
</contactInfo>
<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>
</CI_ResponsibleParty>
</contact>
</MD_Metadata>
XSL 转换:
<?xml version="1.0" encoding="UTF-8"?>
<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"
xmlns:gco="http://www.isotc211.org/schemas/2005/gco"
xmlns:gmd="http://www.isotc211.org/schemas/2005/gmd"
>
<xsl:output indent="yes" encoding="UTF-8"/>
<xsl:strip-space elements="*"/>
<!-- default: identity template -->
<xsl:template match="node() | @*">
<xsl:choose>
<xsl:when test="namespace-uri() eq 'http://www.isotc211.org/schemas/2005/gmd'">
<xsl:element name="gmd:name()" namespace="http://www.isotc211.org/schemas/2005/gmd">
<xsl:copy-of select="namespace::*"/>
<xsl:apply-templates select="node() | @*"/>
</xsl:element>
</xsl:when>
<xsl:otherwise>
<xsl:copy>
<xsl:apply-templates select="node() | @*" />
</xsl:copy>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<!-- override: <CI_Contact>, reorder -->
<xsl:template match="gmd:CI_Contact">
<xsl:copy>
<xsl:apply-templates select="@*" />
<xsl:apply-templates select="gmd:phone" />
<xsl:apply-templates select="gmd:address" />
<xsl:if test="not(gmd:address)">
<gmd:address>
<gmd:CI_Address>
<gmd:electronicMailAddress>
<gco:CharacterString/>
</gmd:electronicMailAddress>
</gmd:CI_Address>
</gmd:address>
</xsl:if>
<xsl:copy-of select="gmd:onlineResource" />
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
我的实际结果:
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="c:\ISO19139_rve.xsl"?>
<gmd: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"
xmlns:gmd="http://www.isotc211.org/schemas/2005/gmd"
xsi:schemaLocation="http://www.isotc211.org/schemas/2005/gmd/gmd.xsd">
<gmd:fileIdentifier>
<gco:CharacterString>b0101011_Vincolo</gco:CharacterString>
</gmd:fileIdentifier>
<gmd:language>
<gco:CharacterString>IT</gco:CharacterString>
</gmd:language>
<gmd:contact>
<gmd:CI_ResponsibleParty>
<gmd:organizationName>
<gco:CharacterString>Comune di Conselve (capofila PATI)</gco:CharacterString>
</gmd:organizationName>
<gmd:role>
<gmd:CI_RoleCode codeList="./resource/codeList.xml#CI_RoleCode" codeListValue="Autore">Autore</gmd:CI_RoleCode>
</gmd:role>
<gmd:contactInfo>
<CI_Contact>
<gmd:phone>
<gmd:CI_Telephone>
<gmd:voice>
<gco:CharacterString>0499596511</gco:CharacterString>
</gmd:voice>
</gmd:CI_Telephone>
</gmd:phone>
<gmd:address>
<gmd:CI_Address>
<gmd:electronicMailAddress>
<gco:CharacterString/>
</gmd:electronicMailAddress>
</gmd:CI_Address>
</gmd:address>
<onlineResource>
<CI_OnlineResource>
<linkage>
<URL>http://www.comune.conselve.it</URL>
</linkage>
</CI_OnlineResource>
</onlineResource>
</CI_Contact>
</gmd:contactInfo>
<gmd:temporalElement>
<gmd:EX_TemporalExtent>
<gmd: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>
</gmd:extent>
</gmd:EX_TemporalExtent>
</gmd:temporalElement>
</gmd:CI_ResponsibleParty>
</gmd:contact>
</gmd:MD_Metadata>
如您所见,转换仅适用于其他模板不匹配的元素。查看<CI_Contact>
、<onlineResource>
、<CI_OnlineResource>
等的结果。
【问题讨论】:
当您说“出于验证目的,我需要为转换结果文件的每个元素添加命名空间前缀。”时,是什么样的验证?基于正常模式的验证检查节点的命名空间,但不检查前缀,因为它们无关紧要,元素<foo xmlns="http://example.com/">...</foo>
与 <pf:foo xmlns:pf="http://example.com/">...</foo>
一样有效。
This 是 INSPIRE 标准验证。还有 GeoNetwork 元数据导入工具。
【参考方案1】:
我会写
<xsl:template match="node() | @*">
<xsl:choose>
<xsl:when test="namespace-uri() eq 'http://www.isotc211.org/schemas/2005/gmd'">
<xsl:element name="gmd:name()" namespace="http://www.isotc211.org/schemas/2005/gmd">
<xsl:copy-of select="namespace::*"/>
<xsl:apply-templates select="node() | @*"/>
</xsl:element>
</xsl:when>
<xsl:otherwise>
<xsl:copy>
<xsl:apply-templates select="node() | @*" />
</xsl:copy>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
作为两个模板
<xsl:template match="node() | @*">
<xsl:copy>
<xsl:apply-templates select="node() | @*" />
</xsl:copy>
</xsl:template>
<xsl:template match="gmd:*">
<xsl:element name="gmd:local-name()" namespace="http://www.isotc211.org/schemas/2005/gmd">
<xsl:copy-of select="namespace::*"/>
<xsl:apply-templates select="node() | @*"/>
</xsl:element>
</xsl:template>
当然,如果您有其他模板匹配和转换 http://www.isotc211.org/schemas/2005/gmd
命名空间中的元素,那么您需要确保在它们中也完成前缀更改,例如
<!-- override: <CI_Contact>, reorder -->
<xsl:template match="gmd:CI_Contact">
<xsl:element name="gmd:local-name()" namespace="http://www.isotc211.org/schemas/2005/gmd">
<xsl:apply-templates select="@*" />
<xsl:apply-templates select="gmd:phone" />
<xsl:apply-templates select="gmd:address" />
<xsl:if test="not(gmd:address)">
<gmd:address>
<gmd:CI_Address>
<gmd:electronicMailAddress>
<gco:CharacterString/>
</gmd:electronicMailAddress>
</gmd:CI_Address>
</gmd:address>
</xsl:if>
<xsl:copy-of select="gmd:onlineResource" />
</xsl:element>
</xsl:template>
【讨论】:
您的解决方案在此示例 XML 文件上运行良好,但是将其放在我的原始转换中会得到一些元素,其中声明了 all namespaces ... 所以,我的另一个解决方案found 是替换每个模板上的根元素。因此,而不是:<xsl:template match="gmd:CI_Contact"> <xsl:element name="gmd:local-name()" namespace="http://www.isotc211.org/schemas/2005/gmd"> <xsl:apply-templates select="@*" />...
如您所写,我使用了:<xsl:template match="gmd:CI_Contact"> <gmd:CI_Contact> <xsl:apply-templates select="@*" />...
以上是关于XSLT 将命名空间前缀添加到元素最佳实践的主要内容,如果未能解决你的问题,请参考以下文章