【问题标题】:XML sorting/formatting tool [closed]XML 排序/格式化工具 [关闭]
【发布时间】:2010-11-28 06:49:16
【问题描述】:

是否有任何工具可以(漂亮打印)格式化 XML 文件以及对其元素和属性进行排序?

【问题讨论】:

标签: xml formatting


【解决方案1】:

由于 Visual Studio 似乎一直在重新排序和重写 EDMX 文件(实体框架)(另请参见 Uservoice),我写了一些 Linqpad 代码来重新排序东西。然而,在 LinqPad 之外使用它很容易(也很明显)。

它按元素类型(标签)对元素进行排序,然后是元素属性“名称”的值,然后是其他一些东西,试图使其具有确定性(不同的 xml,但含义相同, [通常] 是相同的输出 - 请参阅代码)。

它还对属性进行排序。请注意,语义上 XML 属性可能没有(相关)顺序,但 文本上它们有,并且版本控制系统仍然认为它们是纯文本...

(注意它不修复不同的别名,在Entity Framework edmx file regenerating differently amongst team中提到)

void Main()
{
    XDocument xdoc = XDocument.Load(@"\\filepath1\file1.edmx");

    var orderedElements = CopyAndSortElements(xdoc.Elements());

    var newDoc = new XDocument();
    newDoc.Add(orderedElements);
    newDoc.Save(@"\\filepath1\file1.Ordered.edmx");
}

public IEnumerable<XElement> CopyAndSortElements(IEnumerable<XElement> elements)
{
    var newElements = new List<XElement>();
    // Sort XElements by Tag & name-attribute (and some other properties)
    var orderedElements = elements.OrderBy(elem => elem.Name.LocalName) // element-tag
                                  .ThenByDescending(elem => elem.Attributes("Name").Count()) // can be 0, more than 1 is invalid XML
                                  .ThenBy(elem => (elem.Attributes("Name").Any() ? elem.Attributes("Name").First().Value.ToString() : string.Empty))
                                   // in case of no Name-Attributes, try to sort by (number of) children
                                  .ThenBy(elem => elem.Elements().Count())
                                  .ThenBy(elem => elem.Attributes().Count())
                                  // next line may vary for textually different but semantically equal input when elem & attr were unordered on input, but I need to restrain myself...
                                  .ThenBy(elem => elem.ToString());
    foreach (var oldElement in orderedElements)
    {
        var newElement = new XElement(oldElement.Name);
        if (oldElement.HasElements == false && string.IsNullOrEmpty(oldElement.Value) == false)
        {
            // (EDMX does not have textual nodes, but SO-users may use it for other XML-types ;-) )
            // IsNullOrEmpty-check: not setting empty value keeps empty-element tag, setting value (even empty) causes start-tag immediately followed by an end-tag
            // (empty-element tags may be a matter of taste, but for textual comparison it will matter!)
            newElement.Value = oldElement.Value;
        }
        var orderedAttrs = oldElement.Attributes().OrderBy(attr => attr.Name.LocalName).ThenBy(attr => attr.Value.ToString());
        newElement.Add(orderedAttrs);
        newElement.Add(CopyAndSortElements(oldElement.Elements()));
        newElements.Add(newElement);
    }
    return newElements;
}

PS:我们最终使用了其他人同时编写的 XSLT。我认为它在每个人的构建过程中都更容易/更好。 但也许/希望这对某人有用。

【讨论】:

  • 你最终使用了什么 xslt?
  • 呃,看这个——它会从像&lt;thing&gt; value &lt;/thing&gt;这样的节点中删除值
  • @CADbloke,我添加了一些代码用于节点中的文本值。
  • @StevenT.Cramer,对不起,我现在才注意到你的问题,我不记得了。
【解决方案2】:

当我试图弄清楚如何排序和 edmx 文件时,我偶然发现了这篇文章。 我的解决方案基于找到的 Arvo Bowens 解决方案 https://stackoverflow.com/a/19324438/212241

void Main()
{
    XDocument xdoc = XDocument.Load(@"C:\git\Nvision\Source\NvisionEntities\NvisionModel.edmx");
    Sort(xdoc.Root);
    xdoc.Save(@"C:\git\Nvision\Source\NvisionEntities\NvisionModel.edmx");
}

public void Sort(XElement source, bool bSortAttributes = true)
{
    //Make sure there is a valid source
    if (source == null) throw new ArgumentNullException("source");

    //Sort attributes if needed
    if (bSortAttributes)
    {
        List<XAttribute> sortedAttributes = source.Attributes().OrderBy(a => a.ToString()).ToList();
        sortedAttributes.ForEach(a => a.Remove());
        sortedAttributes.ForEach(a => source.Add(a));
    }

    //Sort the children IF any exist
    List<XElement> sortedChildren = source.Elements().OrderBy(elem => elem.Attributes("Name").Any() ? elem.Attributes("Name").First().Value.ToString() : string.Empty).ToList();
    if (source.HasElements)
    {
        source.RemoveNodes();
        sortedChildren.ForEach(c => Sort(c));
        sortedChildren.ForEach(c => source.Add(c));
    }
}

【讨论】:

    【解决方案3】:

    我喜欢这个工具:https://xmlsorter.codeplex.com/

    您可以按标签名称和属性进行排序。我喜欢在比较一些 XML 文件之前使用它。

    【讨论】:

    • 这甚至不会加载 XML 文件。收到“无效的 XML”错误。无法处理 doctype 标签。一旦删除它就起作用了。
    • 这对我有用,可以快速测试一对超过 7K 行且具有半复杂 xml 结构的文件,所以我最初印象深刻。完全没有错误。流畅/快速的下载、启动和执行。值得注意的一件事是它允许“排序属性”和“排序特定属性”,然后您可以在哪里选择您想要的。您可以检查两个似乎重叠的选项。
    • 它是“排序属性”和“排序by特定属性”,非常不同。第一个命令每行的属性,第二个按特定属性的内容对所有行进行排序。我认为后者非常实用。
    • 看来CodePlex马上就要关闭了,页面还在webarchive上但是项目存档没有链接到页面,所以这是webarchiveweb.archive.org/web/20210309105113/https://…中项目存档的链接@
    【解决方案4】:

    我一直在寻找类似的实用程序,但并没有真正找到我想要的东西,所以我只是勉强写了一个。它非常简单(并且不包括节点排序中的属性),但是很有效。

    也许它对其他人有用.. 它在GitHub 上。

    这里有一些来自 GitHub 页面...

    USAGE: sortxml.exe [options] infile [outfile]
    
      infile      The name of the file to sort, etc.
      outfile     The name of the file to save the output to.
                  If this is omitted, then the output is written to stdout.
    
    OPTIONS:
    
      --pretty    Ignores the input formatting and makes the output look nice.
      --sort      Sort both the nodes and attributes.
      --sortnode  Sort the nodes.
      --sortattr  Sort the attributes.
    
    (prefix an option with ! to turn it off.)
    

    默认是输出漂亮和排序的节点和属性。这是一个例子:

    > type sample.xml
    <?xml version="1.0" encoding="utf-8" ?><root><node value="one" attr="name"/></root>
    
    > sortxml.exe sample.xml
    <?xml version="1.0" encoding="utf-8"?>
    <root>
      <node attr="name" value="one" />
    </root>
    

    【讨论】:

      【解决方案5】:

      我发现了这篇文章:http://www.biglist.com/lists/xsl-list/archives/200106/msg01225.html,它使用以下 XSLT 来缩进 XML 并对属性进行排序:

      <?xml version="1.0"?>
      <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
      
        <xsl:output method="xml" indent="yes"/>
        <xsl:strip-space elements="*"/>
      
        <xsl:template match="/">
          <xsl:apply-templates/>
        </xsl:template>
      
        <xsl:template match="*">
          <xsl:copy>
            <!-- Sort the attributes by name. -->
            <xsl:for-each select="@*">
              <xsl:sort select="name( . )"/>
              <xsl:copy/>
            </xsl:for-each>
            <xsl:apply-templates/>
          </xsl:copy>
        </xsl:template>
      
        <xsl:template match="text()|comment()|processing-instruction()">
          <xsl:copy/>
        </xsl:template>
      
      </xsl:stylesheet>
      

      我还没有尝试过,但很可能我会坚持使用 XSLT 为我进行格式化。

      【讨论】:

      • 这对 xml 属性的排序很好,我怎样才能对标签的子元素进行排序?
      • 完美解决方案。它按字母顺序对所有属性进行排序。谢谢!
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-03-29
      • 1970-01-01
      • 2013-03-13
      • 1970-01-01
      • 2021-01-23
      • 2011-01-21
      • 2010-12-04
      相关资源
      最近更新 更多