我已经搜索过谷歌和Stack Overflow,并且无法找到答案。如果这是重复的话我很抱歉。
我有一个XML文档,它有一些嵌套类型;但是,整个文档中出现了几个重复元素,它们都有不同的名称和父母。与XSD相比,实际上发现这些重复元素是相同类型的对象,仅在整个过程中引用。大约有50种不同的类型引用了这个重复元素。如何编写一个模板,然后可以从我需要编写的50个模板中的每个模板内部调用,这样我就不必为每个父类型复制变换了?
例如:
<Model1>
<Description>desc1</Description>
<Code>code1</Code>
<type>VMO</type>
<Model2>
<Description>desc1</Description>
<Code>code1</Code>
<type>VMO</type>
</Model2>
</Model1>
<Model3>
<Description>desc1</Description>
<Code>code1</Code>
<type>VMO</type>
<Model4>
<Model5>
<Description>desc1</Description>
<Code>code1</Code>
<type>VMO</type>
<Model6>
<Description>desc1</Description>
<Code>code1</Code>
<type>VMO</type>
</Model6>
</Model5>
<Code>code1</Code>
<type>VMO</type>
</Model4>
</Model3>
<Model7>
<Description>desc1</Description>
<Code>code1</Code>
<type>VMO</type>
<Model8>
<Description>desc1</Description>
<Code>code1</Code>
<type>VMO</type>
</Model8>
</Model7>
&#13;
例如,在上面的示例中,Model2
,Model6
和Model8
是相同的结构,我需要对每个元素应用相同的转换。我想做这样的事情:
<xsl:template match="Model1">
<xsl:copy>
<!-- maps all other elements -->
<xsl:apply-templates select="someSpecialFunction(Model3)" />
</xsl:copy>
</xsl:template>
<xsl:template match="Model5">
<xsl:copy>
<!-- maps all other elements -->
<xsl:apply-templates select="someSpecialFunction(Model6)" />
</xsl:copy>
</xsl:template>
<xsl:template match="Model7">
<xsl:copy>
<!-- maps all other elements -->
<xsl:apply-templates select="someSpecialFunction(Model8)" />
</xsl:copy>
</xsl:template>
&#13;
并简单地转换父元素。这可能吗?
我知道我可以这样做:
<xsl:template match="Model1/Model3">
<xsl:copy>
<!-- Transfrom type -->
<xsl:apply-templates select="node()|@*" />
</xsl:copy>
</xsl:template>
<xsl:template match="Model5/Model6">
<xsl:copy>
<!-- Transfrom type -->
<xsl:apply-templates select="node()|@*" />
</xsl:copy>
</xsl:template>
<xsl:template match="Model7/Model8">
<xsl:copy>
<!-- Transfrom type -->
<xsl:apply-templates select="node()|@*" />
</xsl:copy>
</xsl:template>
&#13;
然后我重复了很多代码。有什么建议吗?
修改
我在原帖中过于笼统,抱歉。 一个更具体的例子(在我的例子中,是我拥有的对象之一)将是一个地址和与它们相关联的子类型。几种不同类型的元素具有地址。例如,我有一个Product元素,其中包含卖方,供应商,转售商,利益相关者列表,每个都有一个地址等。每个地址都有不同的名称。
<Product>
<Seller>
<BusinessAddress>...</BusinessAddress>
<DistributionAddress>...</DistributionAddress>
<MainContactAddress>...</MainContactAddress>
</Seller>
<ReSeller>
<BusinessAddress>...</BusinessAddress>
<StoreManagerAddress>...</StoreManagerAddress>
<MainContactAddress>...</MainContactAddress>
</ReSeller>
<Supplier>
<BusinessAddress>...</BusinessAddress>
<DistributionCenterAddress>...</DistributionCenterAddress>
<MainContactAddress>...</MainContactAddress>
</Supplier>
<Stakeholders>
<Entity>
<HomeAddress>...</HomeAddress>
<WorkAddress>...</WorkAddress>
<SecondaryAddress>...</SecondaryAddress>
<Street>...</Street>
<CrossStreet>...</CrossStreet>
</Entity>
</Stakeholders>
</Product>
<SurveyRespondents>
<SurveyRespondent>
<Address>...</Address>
<Business>...</Business>
</SurveyRespondent>
<SurveyRespondent>
<Address>...</Address>
<Business>...</Business>
</SurveyRespondent>
</SurveyRespondents>
&#13;
现在这不是所有具有地址的元素,但是如果我采用我之前已经完成的方法,我将不得不制作一个模板列表(如我上面提到的)或者长时间使用像michael.hor257k建议的比赛列表。
<xsl:template match="Address | Business | SecondaryAddress | WorkAddress | Home | SecondaryAddress | BusinessAddress | ...">
<!-- apply the same transform to all of these -->
</xsl:template>
&#13;
为了解决我的问题,每个地址由多个子类型组成:AddressCategory,District,Zone,Street,StreetType,PostDirection,PreDirection等。这些类型中的每一个都具有相同的结构,但现在我遇到了如何匹配每种类型的问题。一些子类型,如Street
,在某些地方(在其他元素中使用时)和#34; CodeType&#34;在其他人。如果我做了一场比赛,我最终会看到一些非常丑陋的东西,我甚至还没有完成整个文件:
<xsl:template match="Address | Business | SecondaryAddress | WorkAddress | Home | SecondaryAddress | BusinessAddress | ...">
<!-- apply the same transform to all of these -->
</xsl:template>
<xsl:template match="Address/Street | Business/Street | SecondaryAddress/Street | WorkAddress/Street | Home/Street | SecondaryAddress/Street | BusinessAddress/Street | AddressType | District | Zone...">
<!-- apply the same transform to all of these -->
</xsl:template>
&#13;
我是否坚持使用难以阅读,调试和维护xslt是更好的方法吗?
答案 0 :(得分:1)
很难回答你的问题,因为它完全与上下文有关 - 并且你没有提供完整的上下文。
例如,在上面的示例中,Model2,Model6和Model8是 相同的结构,我需要对每个元素应用相同的转换
你为什么不这样做:
<xsl:template match="Model2 | Model6 | Model8">
<!-- apply the same transform to all of these -->
</xsl:template>
请注意,此模板可以从任何父节点应用 一个Model2和/或Model6和/或Model8(实际上,它也可以从其他上下文中应用,但这可能不是这里的重点)。
如何编写一个可以从内部调用的模板 我需要编写的50个模板中的每一个
您确定需要编写50个模板吗?
重新编辑:
替代:
<xsl:template match="Address | Business | SecondaryAddress | WorkAddress | Home | SecondaryAddress | BusinessAddress | ...">
<!-- apply the same transform to all of these -->
</xsl:template>
将是:
<xsl:template name="address">
<xsl:param name="address-node" />
<!-- apply the transform -->
</xsl:template>
但是您必须从存在地址的每个位置显式调用此模板,例如:
<xsl:template match="Seller">
<xsl:copy>
<!-- other code -->
<xsl:call-template name="address">
<xsl:with-param name="address-node" select="BusinessAddress"/>
</xsl:call-template>
<xsl:call-template name="address">
<xsl:with-param name="address-node" select="DistributionAddress"/>
</xsl:call-template>
<xsl:call-template name="address">
<xsl:with-param name="address-node" select="MainContactAddress"/>
</xsl:call-template>
<!-- more code -->
</xsl:copy>
</xsl:template>
可能会缩短为:
<xsl:template match="Seller">
<xsl:copy>
<!-- other code -->
<xsl:call-template name="address">
<xsl:with-param name="address-nodes" select="BusinessAddress | DistributionAddress | MainContactAddress"/>
</xsl:call-template>
<!-- more code -->
</xsl:copy>
</xsl:template>
即便如此,我也不确定替代方案是否比最初的建议更具吸引力。
答案 1 :(得分:1)
如果您可以访问支持模式的XSLT 2.0处理器,这将变得非常简单。您可以定义一个模板规则,该规则匹配具有给定类型T
的所有元素,如下所示:
<xsl:template match="element(*, T)">
或者如果所有元素都在模式中定义为属于头部为元素H
的替换组,则可以编写
<xsl:template match="schema-element(H)">
如果没有架构感知处理器,则必须定义联合模式
<xsl:template match="A|B|C|D|E|F....">
并记住每次架构更改时都要更改它。