0

我需要基于 xpaths 在两个 xml 之间动态转换。例如,我有源 xml,它看起来像:

<Source>  
 <ZeroLine>
   <FirstLine>
     <Name>Name1</Name>
     <SurName>SurName1</SurName>
   </FirstLine>
   <FirstLine>
     <Name>Name2</Name>
     <SurName>SurName2</SurName>
   </FirstLine>
 </ZeroLine>
 <ZeroLine>
   <FirstLine>
     <Name>Name3</Name>
     <SurName>SurName3</SurName>
   </FirstLine>
   <FirstLine>
     <Name>Name4</Name>
     <SurName>SurName4</SurName>
   </FirstLine>
 </ZeroLine>
</Source>

我需要将此源 xml 转换为可以具有不同结构的目标 xml。此目标 xml 结构是基于 xPath 构建的。

目标 xml 可以如下所示:

<Target>
  <TargetZeroLine>
    <TargetFirstLine>
      <NameIdentifikator>Name1</NameIdentifikator>
      <SurNameIdentifikator>SurName1</SurNameIdentifikator>
    </TargetFirstLine>
    <TargetFirstLine>
      <NameIdentifikator>Name2</NameIdentifikator>
      <SurNameIdentifikator>SurName2</SurNameIdentifikator>
    </TargetFirstLine>
  </TargetZeroLine>
  <TargetZeroLine>
    <TargetFirstLine>
      <NameIdentifikator>Name3</NameIdentifikator>
      <SurNameIdentifikator>SurName3</SurNameIdentifikator>
    </TargetFirstLine>
    <TargetFirstLine>
      <NameIdentifikator>Name4</NameIdentifikator>
      <SurNameIdentifikator>SurName4</SurNameIdentifikator>
    </TargetFirstLine>
  </TargetZeroLine>
</Target>

此示例的 XPath 规则是:

源 XPath -> 目标 Xpath

源/ZeroLine/FirstLine/Name -> 目标/TargetZeroLine/TargetFirstLine/NameIdentifikator

源/ZeroLine/FirstLine/SurName -> 目标/TargetZeroLine/TargetFirstLine/SurNameIdentifikator

我只有源 xml(xsd) 和这些 xpaths 规则,我需要动态构建将创建目标 xml 的 xslt 转换。

我可以手动编写这个 xslt,它可以像我想要的那样工作,但我需要根据不同的 xPaths 规则动态构建它。对于此示例,xslt 转换如下所示:

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

<xsl:template match="Source">
    <xsl:element name="Target">         
        <xsl:apply-templates select="ZeroLine"/>            
    </xsl:element>                  
</xsl:template>

<xsl:template match="ZeroLine">
    <xsl:element name="TargetZeroLine"> 
        <xsl:apply-templates select="FirstLine"/>
    </xsl:element>      
</xsl:template>

<xsl:template match="FirstLine">
    <xsl:element name="TargetFirstLine">            
        <xsl:element name="NameIdentifikator">
            <xsl:value-of select="Name"/>
        </xsl:element>                  
        <xsl:element name="SurNameIdentifikator">
            <xsl:value-of select="SurName"/>
        </xsl:element>                  
    </xsl:element>                  
</xsl:template>

</xsl:stylesheet>

我的问题是什么?:) 问题是如何从 xPath 为目标构建 xslt。当我知道目标 xml 的外观时,我可以手动编写此模板。

例如,我可以为此 XPath 手动编写 xslt 模板:

Target/TargetZeroLine/TargetFirstLine/NameIdentifikator

这是:

<xsl:template match="FirstLine">
    <xsl:element name="TargetFirstLine">            
        <xsl:element name="NameIdentifikator">
            <xsl:value-of select="Name"/>                 
                    </xsl:element>            
    </xsl:element>                  
</xsl:template>

但是如何编写将动态生成此 xslt 的 C# 代码?因为我不知道应该生成哪个 xsl:element... 到哪个模板。

或者问题也可以是:是否可以基于 xPath 编写 xslt xsl:element?我的意思是这样的:

<xsl:template match="FirstLine">
    <xsl:element name="Target/TargetZeroLine/TargetFirstLine">          
        <xsl:element name="NameIdentifikator">

我希望,我的问题将是清楚的理解。

更新1

XPath 规则在源和目标之间可能不同。层次结构的级别也可以不同。例如以下 XPath 规则:

Source/ZeroLine/FirstLine/Name -> Target/NameSection/NameIdentifikator
Source/ZeroLine/FirstLine/SurName -> Target/SurNameSection/SurNameIdentifikator

应该产生以下预期的 xml:

<Target>
<NameSection>
    <NameIdentifikator>Name1</NameIdentifikator>
    <NameIdentifikator>Name2</NameIdentifikator>
    <NameIdentifikator>Name3</NameIdentifikator>
    <NameIdentifikator>Name4</NameIdentifikator>
</NameSection>
<SurNameSection>
    <SurNameIdentifikator>SurName1</SurNameIdentifikator>
    <SurNameIdentifikator>SurName2</SurNameIdentifikator>
    <SurNameIdentifikator>SurName3</SurNameIdentifikator>
    <SurNameIdentifikator>SurName4</SurNameIdentifikator>
</SurNameSection>
</Target>

谢谢。

4

2 回答 2

0

您可以使用 XPath 选择元素名称,只需将您的查询与 重叠{},例如:

<xsl:element name="{Target/TargetZeroLine/TargetFirstLine/NameIdentifikator}">
于 2013-07-15T00:03:31.250 回答
0

Perhaps you are over-complicating things here. Looking solely at your input XML and output XML, then one way to write the XSLT stylesheet would be as follows

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:template match="Source">
    <Target>     
        <xsl:apply-templates />            
    </Target>                  
</xsl:template>

<xsl:template match="ZeroLine">
    <TargetZeroLine> 
        <xsl:apply-templates />
    </TargetZeroLine>      
</xsl:template>

<xsl:template match="FirstLine">
    <TargetFirstLine>            
        <xsl:apply-templates />              
    </TargetFirstLine>                  
</xsl:template>

<xsl:template match="Name">
    <NameIdentifikator>            
        <xsl:apply-templates />              
    </NameIdentifikator>                  
</xsl:template>

<xsl:template match="SurName">
    <SurNameIdentifikator>            
        <xsl:apply-templates />              
    </SurNameIdentifikator>                  
</xsl:template>

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

</xsl:stylesheet>

As you can see, it doesn't really worry about the hierarchical structure or position of the elements. There is simply a template for each separate element you wish to rename.

As you can probably see, this leads to each template having the same structure.

<xsl:template match="### INPUT ELEMENT ###">
    <### OUTPUT ELEMENT ###>            
        <xsl:apply-templates />              
    </### OUTPUT ELEMENT ###>                  
</xsl:template>

So, if you did really want to write some C# to generate the XSLT for you, you could simply define a constant with placeholders, like so

public const string TEMPLATE = @"<xsl:template match="{0}">
    <{1}>            
        <xsl:apply-templates />              
    </{1}>                  
</xsl:template>";

Then, assuming you had some way of linking source element names to target element names, you could just do something like this

output.WriteLine(string.Format(TEMPLATE, sourceElement, targetElement));
于 2013-07-15T12:17:01.580 回答