基于xpath转换两个xml

时间:2013-07-14 21:10:32

标签: c# xml xslt xpath

我需要根据xpath动态转换两个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 - &gt;目标Xpath

Source / ZeroLine / FirstLine / Name - &gt;目标/ TargetZeroLine / TargetFirstLine / NameIdentifikator

Source / ZeroLine / FirstLine / SurName - &gt;目标/ TargetZeroLine / TargetFirstLine / SurNameIdentifikator

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

我可以手动编写这个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应该是什么样子时,我可以手动编写这个模板。

E.g。我可以为这个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">

我希望,我的问题可以清楚地理解。

UPDATE1

源和目标之间的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>

感谢。

2 个答案:

答案 0 :(得分:0)

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

<xsl:element name="{Target/TargetZeroLine/TargetFirstLine/NameIdentifikator}">

答案 1 :(得分:0)

也许你在这里过于复杂。仅查看输入XML和输出XML,然后编写XSLT样式表的一种方法如下

<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>

正如您所看到的,它并不真正担心元素的层次结构或位置。您希望重命名的每个单独元素都有一个模板。

正如您可能看到的,这导致每个模板具有相同的结构。

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

所以,如果你真的想写一些C#来为你生成XSLT,你可以简单地用占位符定义一个常量,就像这样

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

然后,假设你有一些方法将源元素名称链接到目标元素名称,你可以做这样的事情

output.WriteLine(string.Format(TEMPLATE, sourceElement, targetElement));