C#将xml属性转换为元素 [英] C# to convert xml attributes to elements

查看:269
本文介绍了C#将xml属性转换为元素的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要的所有属性节点转换成XML文件,在根节点属性之外

I need to convert all attributes to nodes in an XML file, with the exception of attributes in the root node.

我发现了一个类似的问题在这里:<一HREF =http://stackoverflow.com/questions/4223926/xquery-to-convert-attributes-to-tags> XQuery来的属性转换为代码,但我需要做转换在C#。

I found a similar question here: xquery to convert attributes to tags, but I need to do the conversion in C#.

我还发现了一个可能的解决方案使用XLS此处的 [XSL]转换属性值成元素。然而,该解决方案本质上改变的节点名称的属性名和删除属性

I have also found a possible solution using XLS here: [XSL] Convert attribute value into element. However, that solution essentially changes the node name to the attribute name and removes the attribute.

我需要与名称和属性的值创建新的兄弟节点,并删除。属性,但仍保留包含的属性节点

I need to create new sibling nodes with the name and value of the attributes and remove the attributes, but still preserve the node that contained the attributes.

由于以下XML:

<Something xmlns="http://www.something.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.xomething.com segments.xsd">
  <Version>4.0.8</Version>
  <Segments>
    <Segment Name="Test">
      <SegmentField>
        <SegmentIndex>0</SegmentIndex>
        <Name>RecordTypeID</Name>
        <Value Source="Literal">O</Value>
      </SegmentField>
      <SegmentField>
        <SegmentIndex>1</SegmentIndex>
        <Name>OrderSequenceNumber</Name>
        <Value Source="Calculated" Initial="1">Sequence</Value>
      </SegmentField>
      <SegmentField>
        <SegmentIndex>3</SegmentIndex>
        <Name>InstrumentSpecimenID</Name>
        <Value Source="Property">BarCode</Value>
      </SegmentField>
    </Segment>
  </Segments>
</Something>



我需要出示以下XML:

I need to produce the following XML:

<Something xmlns="http://www.something.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.xomething.com segments.xsd">
  <Version>4.0.8</Version>
  <Segments>
    <Segment>
      <Name>Test</Name>
      <SegmentField>
        <SegmentIndex>0</SegmentIndex>
        <Name>RecordTypeID</Name>
        <Value>O</Value>
        <Source>Literal</Source>
      </SegmentField>
      <SegmentField>
        <SegmentIndex>1</SegmentIndex>
        <Name>OrderSequenceNumber</Name>
        <Value>Sequence</Value>
        <Source>Calculated</Source>
        <Initial>1</Initial>
      </SegmentField>
      <SegmentField>
        <SegmentIndex>3</SegmentIndex>
        <Name>InstrumentSpecimenID</Name>
        <Value>BarCode</Value>
        <Source>Property</Source>
      </SegmentField>
    </Segment>
  </Segments>
</Something>



我写了下面的方法来创建一个新的XML对象,从<$ C创建新元素$ C>源元素的属性:

private static XElement ConvertAttribToElement(XElement source)
{
    var result = new XElement(source.Name.LocalName);

    if (source.HasElements)
    {
        foreach (var element in source.Elements())
        {
            var orphan = ConvertAttribToElement(element);

            result.Add(orphan);
        }
    }
    else
    {
        result.Value = source.Value.Trim();
    }

    if (source.Parent == null)
    {
        // ERROR: The prefix '' cannot be redefined from '' to 'http://www.something.com' within the same start element tag.

        //foreach (var attrib in source.Attributes())
        //{
        //    result.SetAttributeValue(attrib.Name.LocalName, attrib.Value);
        //}
    }
    else
    {
        while (source.HasAttributes)
        {
            var attrib = source.LastAttribute;
            result.AddFirst(new XElement(attrib.Name.LocalName, attrib.Value.Trim()));
            attrib.Remove();
        }
    }

    return result;
}

这方法会产生以下XML:

This method produces the following XML:

<Something>
  <Version>4.0.8</Version>
  <Segments>
    <Segment>
      <Name>Test</Name>
      <SegmentField>
        <SegmentIndex>0</SegmentIndex>
        <Name>RecordTypeID</Name>
        <Value>
          <Source>Literal</Source>O</Value>
      </SegmentField>
      <SegmentField>
        <SegmentIndex>1</SegmentIndex>
        <Name>OrderSequenceNumber</Name>
        <Value>
          <Source>Calculated</Source>
          <Initial>1</Initial>Sequence</Value>
      </SegmentField>
      <SegmentField>
        <SegmentIndex>3</SegmentIndex>
        <Name>InstrumentSpecimenID</Name>
        <Value>
          <Source>Property</Source>BarCode</Value>
      </SegmentField>
    </Segment>
  </Segments>
</Something>

有两个与输出直接的问题:结果
1)中的属性根元素都将丢失。结果
2)从值元素的属性作为子元素,而不是兄弟姐妹创建的。

There are two immediate problems with the output:
1) The attributes in the root element are lost.
2) The attributes from the 'Value' element are created as child element instead of siblings.

要解决第一个问题,我试图分配元素添加到结果元素的属性,但已经引起了的前缀''相同的开始元素标记的误差范围内不能从重新定义'到'http://www.something.com。我注释掉导致用于说明错误的代码。

To address the first issue, I tried to assign the attributes of the source element to the result element, but had that caused a "prefix '' cannot be redefined from '' to 'http://www.something.com' within the same start element tag" error. I commented out the code that caused the error for illustration.

要解决的第二个问题,我尝试添加从属性创建到 source.Parent 元素中,但造成了新的元素没有出现在所有。

To address the second issue, I attempted to add the element created from the attribute to the source.Parent element, but that resulted in the new element not appearing at all.

我也改写直接对操作方法元素:

I also rewrote the method to operate directly on the source element:

private static void ConvertAttribToElement2(XElement source)
{
    if (source.HasElements)
    {
        foreach (var element in source.Elements())
        {
            ConvertAttribToElement2(element);
        }
    }

    if (source.Parent != null)
    {
        while (source.HasAttributes)
        {
            var attrib = source.LastAttribute;
            source.Parent.AddFirst(new XElement(attrib.Name.LocalName, attrib.Value.Trim()));
            attrib.Remove();
        }
    }
}



重写产生了以下XML

The rewrite produced the following XML:

<Something xmlns="http://www.something.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.xomething.com segments.xsd">
  <Version>4.0.8</Version>
  <Segments>
    <Name xmlns="">Test</Name>
    <Segment>
      <SegmentField>
        <Source xmlns="">Literal</Source>
        <SegmentIndex>0</SegmentIndex>
        <Name>RecordTypeID</Name>
        <Value>O</Value>
      </SegmentField>
      <SegmentField>
        <Source xmlns="">Calculated</Source>
        <Initial xmlns="">1</Initial>
        <SegmentIndex>1</SegmentIndex>
        <Name>OrderSequenceNumber</Name>
        <Value>Sequence</Value>
      </SegmentField>
      <SegmentField>
        <Source xmlns="">Property</Source>
        <SegmentIndex>3</SegmentIndex>
        <Name>InstrumentSpecimenID</Name>
        <Value>BarCode</Value>
      </SegmentField>
    </Segment>
  </Segments>
</Something>



重写的没有的解决保留根属性的第一个问题元件。这也部分回答了第二个问题,但产生了新的问题:新的元素有一个空白xmlns属性。

The rewrite did resolve the first issue of preserving the attributes of the root element. It also partially addressed the second issue, but has produced a new problem: the new elements have a blank xmlns attribute.

推荐答案

< STRONG>这个XSLT转换

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:x="http://www.something.com">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:variable name="vNamespace" select="namespace-uri(/*)"/>

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

 <xsl:template match="*/*/@*">
  <xsl:element name="{name()}" namespace="{$vNamespace}">
   <xsl:value-of select="."/>
  </xsl:element>
 </xsl:template>

 <xsl:template match="x:Value">
  <xsl:copy>
   <xsl:apply-templates/>
  </xsl:copy>
  <xsl:apply-templates select="@*"/>
 </xsl:template>
</xsl:stylesheet>



时,所提供的XML文档应用:

<Something xmlns="http://www.something.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.xomething.com segments.xsd">
    <Version>4.0.8</Version>
    <Segments>
        <Segment Name="Test">
            <SegmentField>
                <SegmentIndex>0</SegmentIndex>
                <Name>RecordTypeID</Name>
                <Value Source="Literal">O</Value>
            </SegmentField>
            <SegmentField>
                <SegmentIndex>1</SegmentIndex>
                <Name>OrderSequenceNumber</Name>
                <Value Source="Calculated" Initial="1">Sequence</Value>
            </SegmentField>
            <SegmentField>
                <SegmentIndex>3</SegmentIndex>
                <Name>InstrumentSpecimenID</Name>
                <Value Source="Property">BarCode</Value>
            </SegmentField>
        </Segment>
    </Segments>
</Something>



产生完全想要的,正确的结果

<Something xmlns="http://www.something.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.xomething.com segments.xsd">
   <Version>4.0.8</Version>
   <Segments>
      <Segment>
         <Name>Test</Name>
         <SegmentField>
            <SegmentIndex>0</SegmentIndex>
            <Name>RecordTypeID</Name>
            <Value>O</Value>
            <Source>Literal</Source>
         </SegmentField>
         <SegmentField>
            <SegmentIndex>1</SegmentIndex>
            <Name>OrderSequenceNumber</Name>
            <Value>Sequence</Value>
            <Source>Calculated</Source>
            <Initial>1</Initial>
         </SegmentField>
         <SegmentField>
            <SegmentIndex>3</SegmentIndex>
            <Name>InstrumentSpecimenID</Name>
            <Value>BarCode</Value>
            <Source>Property</Source>
         </SegmentField>
      </Segment>
   </Segments>
</Something>



说明


  1. 身份规则/模板复制每个节点原样。

  1. The identity rule/template copies every node "as is".

身份规则被重写两个模板 - 一个匹配是不是文档的顶级元素,另一个匹配任何元素

The identity rule is overriden by two templates -- one matching any attribute of any element that is not the top element of the document, another matching any Value element.

模板匹配属性(第一个压倒一切的模板)创建到位属性具有相同本地名称和值的属性相匹配的元素。此外,该元素的名称被放在同一个命名空间,该文件的顶级元素所属的一个(这避免了的xmlns =)。

The template matching attributes (the first overriding template) creates in place of the attribute an element with the same local name and value as the matched attribute. In addition, the element name is put in the same namespace as the one that the top element of the document belongs to (this avoids the xmlns="").

匹配它,处理它的子树(子节点)的人任何元素复制的模板,然后处理其属性。这样,从属性生成的元素成为兄弟姐妹,而不是元素的子元素。

The template matching any Value element copies it and processes al of its subtree (descendent nodes), then processes its attributes. In this way the elements generated from the attributes become siblings and not children of the Value element.

这篇关于C#将xml属性转换为元素的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆