我正在尝试用程序更新java中的现有XSD,它看起来像这样:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns="com/company/common" xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="com/company/common/" elementFormDefault="qualified">
<xs:include schemaLocation="DerivedAttributes.xsd" />
<xs:element name="MyXSD" type="MyXSD" />
<xs:complexType name="Container1">
<xs:sequence>
<xs:element name="element1" type="element1" minOccurs="0"
maxOccurs="unbounded" />
<xs:element name="element2" type="element2" minOccurs="0"
maxOccurs="unbounded" />
</xs:sequence>
</xs:complexType>
<xs:complexType name="Container2">
<xs:sequence>
<xs:element name="element3" type="Type1" minOccurs="0" />
<xs:element name="element4" type="Type2" minOccurs="0" />
</xs:sequence>
</xs:complexType>
</xs:schema>
使用DOM和XPath,我可以很容易地将新元素添加到容器1中,如下所示:
Document doc = DocumentBuilderFactory.newInstance()
.newDocumentBuilder().parse(
new InputSource("test.xsd"));
// use xpath to find node to add to
XPath xPath = XPathFactory.newInstance().newXPath();
NodeList nodes = (NodeList) xPath
.evaluate(
"/schema/complexType[@name="Container1"]/sequence",
doc.getDocumentElement(), XPathConstants.NODESET);
// create element to add
org.w3c.dom.Element newElement = doc.createElement("xs:element");
newElement.setAttribute("name", "element5");
newElement.setAttribute("type", "type5");
newElement.setAttribute("minOccurs", "0");
newElement.setAttribute("manOccurs", "unbounded");
nodes.item(0).appendChild(newElement);
// output
TransformerFactory.newInstance().newTransformer().transform(
new DOMSource(doc.getDocumentElement()),
new StreamResult(System.out));
我能够得到这样的结果:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns="com/company/common" xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="com/company/common/" elementFormDefault="qualified">
<xs:include schemaLocation="DerivedAttributes.xsd" />
<xs:element name="MyXSD" type="MyXSD" />
<xs:complexType name="Container1">
<xs:sequence>
<xs:element name="element1" type="element1" minOccurs="0"
maxOccurs="unbounded" />
<xs:element name="element2" type="element2" minOccurs="0"
maxOccurs="unbounded" />
<xs:element name="element3" type="element2" minOccurs="0"
maxOccurs="unbounded" />
</xs:sequence>
</xs:complexType>
<xs:complexType name="Container2">
<xs:sequence>
<xs:element name="element3" type="Type1" minOccurs="0" />
<xs:element name="element2" type="Type2" minOccurs="0" />
</xs:sequence>
</xs:complexType>
<xs:complexType name="Container3">
<xs:sequence>
<xs:element name="element4" type="Type1" minOccurs="0" />
</xs:sequence>
</xs:complexType>
</xs:schema>
所以我的问题是如何添加一个名为"Container3"的新复杂类型。。。用一个序列。。。它包含使用相同DOM appach的"元素5",所以它看起来像这样:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns="com/company/common" xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="com/company/common/" elementFormDefault="qualified">
<xs:include schemaLocation="DerivedAttributes.xsd" />
<xs:element name="MyXSD" type="MyXSD" />
<xs:complexType name="Container1">
<xs:sequence>
<xs:element name="element1" type="element1" minOccurs="0"
maxOccurs="unbounded" />
<xs:element name="element2" type="element2" minOccurs="0"
maxOccurs="unbounded" />
</xs:sequence>
</xs:complexType>
<xs:complexType name="Container2">
<xs:sequence>
<xs:element name="element3" type="Type1" minOccurs="0" />
<xs:element name="element4" type="Type2" minOccurs="0" />
</xs:sequence>
</xs:complexType>
<xs:complexType name="Container3">
<xs:sequence>
<xs:element name="element5" type="Type1" minOccurs="0" />
</xs:sequence>
</xs:complexType>
</xs:schema>
现在我正在使用一个DOM解析器,它添加了一个新的复杂类型。。。但我不知道如何创建一个复杂的类型,它也有一个元素的序列。这就是我目前所拥有的。。。
Document doc = DocumentBuilderFactory.newInstance()
.newDocumentBuilder().parse(
new InputSource("test.xsd"));
// use xpath to find node to add to
XPath xPath = XPathFactory.newInstance().newXPath();
NodeList nodes = (NodeList) xPath.evaluate("/schema", doc
.getDocumentElement(), XPathConstants.NODESET);
// create element to add
org.w3c.dom.Element newElement = doc.createElement("xs:complexType");
newElement.setAttribute("name", "Container3");
nodes.item(0).appendChild(newElement);
// output
TransformerFactory.newInstance().newTransformer().transform(
new DOMSource(doc.getDocumentElement()),
new StreamResult(System.out));
谢谢!
首先,一个警告词。如果您想使用XPath,您应该正确处理名称空间-XPath语言只在名称空间格式良好的XML上定义,虽然一些DOM和XPath实现似乎在没有名称空间的情况下解析的DOM树上工作,但这并不能保证,如果您因任何原因换用不同的解析器,事情可能会中断。
考虑到在javax.xml.xpath
中使用名称空间是多么麻烦,我倾向于改用更Java友好的对象模型,如dom4j。
尽管在这种情况下实际上根本不需要使用XPath,因为您只是在文档的根元素中添加了一个新的子元素:
// this is org.dom4j.Document, not w3c
SAXReader reader = new SAXReader();
Document doc = reader.read(new File("test.xsd"));
doc.getRootElement()
.addElement("xs:complexType", "http://www.w3.org/2001/XMLSchema")
.addAttribute("name", "Container4")
.addElement("xs:sequence", "http://www.w3.org/2001/XMLSchema")
.addElement("xs:element", "http://www.w3.org/2001/XMLSchema")
.addAttribute("name", "element5")
.addAttribute("type", "xs:string")
.addAttribute("minOccurs", "0");
System.out.println(doc.asXML());
或者在W3C DOM:中
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
// enable namespaces - for some obscure reason this is false by default
dbf.setNamespaceAware(true);
Document doc = dbf.newDocumentBuilder().parse(
new InputSource("test.xsd"));
// create element to add
org.w3c.dom.Element newComplexType = doc
.createElementNS("http://www.w3.org/2001/XMLSchema", "xs:complexType");
org.w3c.dom.Element newSequence = doc
.createElementNS("http://www.w3.org/2001/XMLSchema", "xs:sequence");
org.w3c.dom.Element newElement = doc
.createElementNS("http://www.w3.org/2001/XMLSchema", "xs:element");
newComplexType.setAttributeNS(null, "name", "Container3");
newElement.setAttributeNS(null, "name", "element5");
newElement.setAttributeNS(null, "type", "type5");
newElement.setAttributeNS(null, "minOccurs", "0");
newElement.setAttributeNS(null, "manOccurs", "unbounded");
doc.getDocumentElement().appendChild(newComplexType)
.appendChild(newSequence).appendChild(newElement);
// output
TransformerFactory.newInstance().newTransformer().transform(
new DOMSource(doc),
new StreamResult(System.out));
考虑到我们处理的XML涉及名称空间,我们必须使用DOM方法的NS
变体,而不是在引入XML名称空间规范之前的古老的非名称空间感知方法。
在我看来,这确实是XSLT应该做的事情。XML模式是一个XML文档,由于您希望将其转换为另一个XML文件,XSLT是实现这一点的完美工具。使用Java和DOM非常复杂(非常主观)。
要执行这个样式表,您需要一个Java中的XSLT处理器,但有很多好的资源可以展示如何做到这一点(这似乎是其中之一)。
XSLT样式表
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xsl:strip-space elements="*"/>
<xsl:output method="xml" encoding="UTF-8" indent="yes" />
<xsl:template match="/*">
<xsl:copy>
<xsl:apply-templates/>
<!--Introduce the new element-->
<xs:complexType name="Container3">
<xs:sequence>
<xs:element name="element5" type="Type1" minOccurs="0" />
</xs:sequence>
</xs:complexType>
</xsl:copy>
</xsl:template>
<!--Identity template, produces an exact copy of the input-->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:transform>
XML输出
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns="com/company/common">
<xs:include schemaLocation="DerivedAttributes.xsd"/>
<xs:element name="MyXSD" type="MyXSD"/>
<xs:complexType name="Container1">
<xs:sequence>
<xs:element name="element1" type="element1" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="element2" type="element2" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="Container2">
<xs:sequence>
<xs:element name="element3" type="Type1" minOccurs="0"/>
<xs:element name="element4" type="Type2" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="Container3">
<xs:sequence>
<xs:element name="element5" type="Type1" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
</xs:schema>
感谢您的建议。虽然@Ian-Roberts解决方案在SAX中可能更优雅,但我能够用DOM这样做:
Document doc = DocumentBuilderFactory.newInstance()
.newDocumentBuilder().parse(
new InputSource("test.xsd"));
// use xpath to find node to add to
XPath xPath = XPathFactory.newInstance().newXPath();
NodeList nodes = (NodeList) xPath.evaluate("/schema", doc
.getDocumentElement(), XPathConstants.NODESET);
// create element to add
org.w3c.dom.Element newComplexType = doc
.createElement("xs:complexType");
org.w3c.dom.Element newSequence = doc.createElement("xs:sequence");
org.w3c.dom.Element newElement = doc.createElement("xs:element");
newComplexType.setAttribute("name", "Container3");
newElement.setAttribute("name", "element5");
newElement.setAttribute("type", "type5");
newElement.setAttribute("minOccurs", "0");
newElement.setAttribute("manOccurs", "unbounded");
nodes.item(0).appendChild(newComplexType).appendChild(newSequence)
.appendChild(newElement);
// output
TransformerFactory.newInstance().newTransformer().transform(
new DOMSource(doc.getDocumentElement()),
new StreamResult(System.out));