Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/370.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java DOM处理后XML属性的顺序_Java_Xml_Dom - Fatal编程技术网

Java DOM处理后XML属性的顺序

Java DOM处理后XML属性的顺序,java,xml,dom,Java,Xml,Dom,当通过标准DOM处理XML时,在序列化后,属性顺序不能得到保证。最后,这就是我在使用标准JavaXML转换API序列化输出时所实现的 不过我确实需要维持秩序。我想知道Java是否有可能保持通过DOM API处理的XML文件属性的原始顺序,或者是否有任何方式强制执行该顺序(可能通过使用允许设置此类属性的替代序列化API)。在我的例子中,处理简化为使用一组属性改变相同元素序列的某些属性(不是全部)的值,并可能插入更多的元素 有没有什么“简单”的方法,或者我必须定义自己的XSLT转换样式表来指定输出并

当通过标准DOM处理XML时,在序列化后,属性顺序不能得到保证。最后,这就是我在使用标准JavaXML转换API序列化输出时所实现的

不过我确实需要维持秩序。我想知道Java是否有可能保持通过DOM API处理的XML文件属性的原始顺序,或者是否有任何方式强制执行该顺序(可能通过使用允许设置此类属性的替代序列化API)。在我的例子中,处理简化为使用一组属性改变相同元素序列的某些属性(不是全部)的值,并可能插入更多的元素

有没有什么“简单”的方法,或者我必须定义自己的XSLT转换样式表来指定输出并修改整个输入XML文件

更新我必须感谢您的所有回答。答案现在似乎比我预期的更为明显。我从来没有注意过属性顺序,因为我以前从未需要它

需要属性顺序的主要原因是生成的XML文件看起来不同。目标是一个包含数百个报警的配置文件(每个报警由一组属性定义)。随着时间的推移,这个文件通常很少修改,但是保持它的有序是很方便的,因为当我们需要修改某些东西时,它是手工编辑的。有时,一些项目需要对此文件进行少量修改,例如将其中一个属性设置为特定于客户的代码

我刚刚开发了一个小应用程序,用于将原始文件(所有项目通用)与每个项目的特定部分合并(修改某些属性的值),以便特定于项目的文件获得基本文件的更新(新的报警定义或某些属性值错误修复)。我要求有序属性的主要动机是能够通过文本比较工具(如Winmerge)检查应用程序相对于原始文件的输出。如果格式(主要是属性顺序)保持不变,那么很容易发现差异


我真的认为这是可能的,因为XML处理程序,比如XMLSpy,允许您编辑XML文件并应用一些排序(网格模式)。也许我唯一的选择就是使用这些程序中的一个来手动修改输出文件。

您真的不需要保持任何顺序。据我所知,在验证XML文档时,也没有模式考虑属性顺序。听起来,在另一端处理XML的任何东西都没有使用适当的DOM来解析结果


我想一种选择是使用字符串构建手动构建文档,但我强烈建议不要这样做。

您真的不需要保持任何顺序。据我所知,在验证XML文档时,也没有模式考虑属性顺序。听起来,在另一端处理XML的任何东西都没有使用适当的DOM来解析结果


我认为一种选择是使用字符串构建手动构建文档,但我强烈建议不要这样做。

请参阅XML建议的第3.1节。它说,“请注意,属性规范在开始标记或空元素标记中的顺序并不重要。”

如果一个软件要求XML元素的属性以特定的顺序出现,那么该软件不是在处理XML,而是在处理表面上类似XML的文本。它需要修复

如果无法修复,并且必须生成符合其要求的文件,则无法可靠地使用标准XML工具生成这些文件。例如,您可以尝试(如您所建议的)使用XSLT以定义的顺序生成属性,例如:

<test>
   <xsl:attribute name="foo"/>
   <xsl:attribute name="bar"/>
   <xsl:attribute name="baz"/>
</test>

只发现XSLT处理器发出以下消息:

<test bar="" baz="" foo=""/>

因为处理器使用的DOM按标记名的字母顺序排列属性。(这是XML DOM中常见但不通用的行为。)


但我想强调一点。如果一个软件在一个方面违反了XML建议,那么它可能在其他方面违反了它。如果以错误的顺序馈送属性时它会中断,那么如果使用单引号分隔属性,或者如果属性值包含字符实体,它可能也会中断,或者是XML推荐中提到的一个XML文档可以做一些本软件作者可能没有想到的事情中的任何一件。

看看XML推荐的第3.1节。它说,“请注意,属性规范在开始标记或空元素标记中的顺序并不重要。”

如果一个软件要求XML元素的属性以特定的顺序出现,那么该软件不是在处理XML,而是在处理表面上类似XML的文本。它需要修复

如果无法修复,并且必须生成符合其要求的文件,则无法可靠地使用标准XML工具生成这些文件。例如,您可以尝试(如您所建议的)使用XSLT以定义的顺序生成属性,例如:

<test>
   <xsl:attribute name="foo"/>
   <xsl:attribute name="bar"/>
   <xsl:attribute name="baz"/>
</test>

只发现XSLT处理器发出以下消息:

<test bar="" baz="" foo=""/>

因为处理器使用的DOM按标记名的字母顺序排列属性。(这是XML DOM中常见但不通用的行为。)

但我想强调一点。如果一个软件在一个方面违反了XML建议,那么它可能在其他方面违反了它。如果以错误的顺序提供属性时它会中断,那么如果使用单引号分隔属性,或者如果属性值包含字符实体,或者XML建议中说XML文档可以做到的其他十几件事情中的任何一件,那么它可能也会断开
<foo attr1="a" attr2="b" attr3="c" theMostImportantAttribute="attr1" />
SAXParserFactory spf = SAXParserFactoryImpl.newInstance();
spf.setNamespaceAware(true);
spf.setValidating(false);
spf.setFeature("http://xml.org/sax/features/validation", false);
spf.setFeature("http://apache.org/xml/features/nonvalidating/load-dtd-grammar", false);
spf.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
SAXParser sp = spf.newSAXParser() ;
Source src = new SAXSource ( sp.getXMLReader(), new InputSource( input.getAbsolutePath() ) ) ;
String resultFileName = input.getAbsolutePath().replaceAll(".xml$", ".cooked.xml" ) ;
Result result = new StreamResult( new File (resultFileName) ) ;
TransformerFactory tf = TransformerFactory.newInstance();
Source xsltSource = new StreamSource( new File ( COOKER_XSL ) );
xsl = tf.newTransformer( xsltSource ) ;
xsl.setParameter( "srcDocumentName", input.getName() ) ;
xsl.setParameter( "srcDocumentPath", input.getAbsolutePath() ) ;

xsl.transform(src, result );
<h50row a="1" xidx="1" c="1"></h50row>
<h50row a="2" b="2" xidx="2"></h50row>
<h50row xidx="1" a="1" c="1"></h50row>
<h50row xidx="2" a="2" b="2"></h50row>
test = "<h50row a=\"1\" xidx=\"1\" c=\"1\"></h50row>";
test = test.replaceAll("(<h5.*row)(.*)(.xidx=\"\\w*\")([^>]*)(>)", "$1$3$2$4$5");
package mynewpackage;

// for the method
import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

// for the test example
import org.xml.sax.InputSource;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.StringReader;
import org.w3c.dom.Document;
import java.math.BigDecimal;

public class NodeTools {
    /**
     * Method sorts any NodeList by provided attribute.
     * @param nl NodeList to sort
     * @param attributeName attribute name to use
     * @param asc true - ascending, false - descending
     * @param B class must implement Comparable and have Constructor(String) - e.g. Integer.class , BigDecimal.class etc
     * @return 
     */
    public static Node[] sortNodes(NodeList nl, String attributeName, boolean asc, Class<? extends Comparable> B)
    {        
        class NodeComparator<T> implements Comparator<T>
        {
            @Override
            public int compare(T a, T b)
            {
                int ret;
                Comparable bda = null, bdb = null;
                try{
                    Constructor bc = B.getDeclaredConstructor(String.class);
                    bda = (Comparable)bc.newInstance(((Element)a).getAttribute(attributeName));
                    bdb = (Comparable)bc.newInstance(((Element)b).getAttribute(attributeName));
                }
                catch(Exception e)
                {
                    return 0; // yes, ugly, i know :)
                }
                ret = bda.compareTo(bdb);
                return asc ? ret : -ret; 
            }
        }

        List<Node> x = new ArrayList<>();
        for(int i = 0; i < nl.getLength(); i++)
        {
            x.add(nl.item(i));
        }
        Node[] ret = new Node[x.size()];
        ret = x.toArray(ret);
        Arrays.sort(ret, new NodeComparator<Node>());
        return ret;
    }    

    public static void main(String... args)
    {
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();  
        DocumentBuilder builder;
        String s = "<xml><item id=\"1\" price=\"100.00\" /><item id=\"3\" price=\"29.99\" /><item id=\"2\" price=\"5.10\" /></xml>";
        Document doc = null;
        try 
        {  
            builder = factory.newDocumentBuilder();  
            doc = builder.parse(new InputSource(new StringReader(s)));
        }
        catch(Exception e) { System.out.println("Alarm "+e); return; }

        System.out.println("*** Sort by id ***");
        Node[] ret = NodeTools.sortNodes(doc.getElementsByTagName("item"), "id", true, Integer.class);

        for(Node n: ret)
        {
            System.out.println(((Element)n).getAttribute("id")+" : "+((Element)n).getAttribute("price"));
        }

        System.out.println("*** Sort by price ***");
        ret = NodeTools.sortNodes(doc.getElementsByTagName("item"), "price", true, BigDecimal.class);
        for(Node n: ret)
        {
            System.out.println(((Element)n).getAttribute("id")+" : "+((Element)n).getAttribute("price"));
        }
    }
}
*** Sort by id ***
1 : 100.00
2 : 5.10
3 : 29.99
*** Sort by price ***
2 : 5.10
3 : 29.99
1 : 100.00