只复制有效的元素和属性?

时间:2014-02-12 21:30:35

标签: xml xslt xsd

我正在尝试使用XSLT将一个XML文档转换为另一个XML文档。是否可以在样式表中指定我只想复制“有效”的元素/属性?有效,我的意思是它们存在于目标模式中。

例如,给定source.xsd:

<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" 
    xmlns:more_emotion="http://example.org/more_emotion"
    targetNamespace="http://example.org/more_emotion"
    elementFormDefault="qualified" 
    attributeFormDefault="qualified">

    <xs:element name="Emotion" type="more_emotion:imComplex"/>
    <xs:complexType name="imComplex">
        <xs:sequence>
            <xs:element name="Joy" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
            <xs:element name="Anger" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
            <xs:element name="Confusion" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
        </xs:sequence>
    </xs:complexType>
</xs:schema>

和destination.xsd:

<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" 
    targetNamespace="http://example.org/emotion"
    xmlns:emotion="http://example.org/emotion"
    elementFormDefault="qualified" 
    attributeFormDefault="qualified">

    <xs:element name="Emotion" type="emotion:imComplex"/>
    <xs:complexType name="imComplex">
        <xs:sequence>
            <xs:element name="Joy" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
        </xs:sequence>
    </xs:complexType>
</xs:schema>

看起来像这样的xml文档

<?xml version="1.0" encoding="UTF-8"?>
<more_emotion:Emotion xmlns:more_emotion="http://example.org/more_emotion">
    <more_emotion:Joy>Hooray!</more_emotion:Joy>
    <more_emotion:Anger>Grrr</more_emotion:Anger>
    <more_emotion:Confusion>Huh?</more_emotion:Confusion>
</more_emotion:Emotion>

是否可以使用XSLT将文档转换为以下,而必须命名要复制或排除的特定元素/属性?

<?xml version="1.0" encoding="UTF-8"?>
<more_emotion:Emotion xmlns:more_emotion="http://example.org/more_emotion">
    <more_emotion:Joy>Hooray!</more_emotion:Joy>
</more_emotion:Emotion>

在伪代码中考虑它我需要像

这样的东西
for each element or attribute in document
    if element or attribute exists in destination schema
        copy element or attribute to destination document
    else
        discard element or attribute

我不知道如何做的部分(或者如果在XSLT中可能的话)是if element or attribute exists in destination schema

1 个答案:

答案 0 :(得分:2)

你想要这么复杂吗?您是否担心检查层次结构中元素的位置以查看它是否与架构中指定的内容相对应?或者它真的只是检查元素名称是否存在于某个地方?

如果你想让它保持“简单”并检查模式中某处指定的元素名称,你可以先使用XSLT身份转换开始

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

这样就可以按原样复制所有节点和属性,因此您只需要为要更改的内容编写模板。或者在您的情况下,对于您不想复制的内容。

使用“文档”功能,您可以拥有一个模板,该模板可以查看架构文档中没有任何具有相同名称的元素,只需忽略该元素。

<xsl:template match="*[not(local-name() = document('destination.xsd')//xs:element/@name)]" />

您可以为属性编写类似的内容。试试这个XSLT开始

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"  xmlns:xs="http://www.w3.org/2001/XMLSchema">
   <xsl:output method="xml" indent="yes"/>

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

   <xsl:template match="*[not(local-name() = document('destination.xsd')//xs:element/@name)]" />

   <xsl:template match="@*[not(local-name() = document('destination.xsd')//xs:attribute/@name)]" />
</xsl:stylesheet>

这应该输出以下内容:

<more_emotion:Emotion xmlns:more_emotion="http://example.org/more_emotion">
   <more_emotion:Joy>Hooray!</more_emotion:Joy>
</more_emotion:Emotion>

请注意,如果您想继续处理“已丢弃”元素的子元素,以查看它们是否匹配,请将第一个模板更改为此

<xsl:template match="*[not(local-name() = document('destination.xsd')//xs:element/@name)]">
   <xsl:apply-templates />
</xsl:template>