我试图以编程方式更新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非常轻松地向Container 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>
所以我的问题是如何添加一个名为&#34;容器3&#34; ...的新复杂类型,其中包含序列...包含&#34;元素5&#34;使用相同的DOM apprach,看起来像这样:
<?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));
谢谢!
答案 0 :(得分:4)
首先,一句警告。如果你想使用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命名空间规范之前的古老的非命名空间感知方法。
答案 1 :(得分:0)
在我看来,你应该用XSLT做些什么。 XML Schema是一个XML文档 - 由于您希望将其转换为另一个XML文档,因此XSLT是完美的工具。使用Java和DOM是无穷无尽的复杂(非常主观)。
要执行此样式表,您需要一个Java中的XSLT处理器,但有许多好的资源显示如何执行此操作(this似乎是其中之一)。
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>
答案 2 :(得分:-1)
感谢您的建议。虽然@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));