使用PL / pgSQL逐步构建XML文档/字符串的最佳方法是什么?考虑以下所需的XML输出:
<Directory>
<Person>
<Name>Bob</Name>
<Address>1234 Main St</Address>
<MagicalAddressFactor1>3</MagicalAddressFactor1>
<MagicalAddressFactor2>8</MagicalAddressFactor2>
<MagicalAddressFactor3>1</MagicalAddressFactor3>
<IsMagicalAddress>Y</IsMagicalAddress>
</Person>
<Person>
<Name>Joshua</Name>
<Address>100 Broadway Blvd</Address>
<MagicalAddressFactor1>2</MagicalAddressFactor1>
<MagicalAddressFactor2>1</MagicalAddressFactor2>
<MagicalAddressFactor3>4</MagicalAddressFactor3>
<IsMagicalAddress>Y</IsMagicalAddress>
</Person>
</Directory>
其中:
我如何使用XML函数生成PL / pgSQL以确保格式良好的XML元素?不使用XML函数,代码看起来像这样:
DECLARE
v_sql text;
v_rec RECORD;
v_XML xml;
v_factor1 integer;
v_factor2 integer;
v_factor3 integer;
v_IsMagical varchar;
BEGIN
v_XML := '<Directory>';
v_sql := 'select * from person;'
FOR v_rec IN v_sql LOOP
v_XML := v_XML || '<Name>' || v_rec.name || '</Name>' ||
'<Address>' || v_rec.Address || '</Address>';
v_factor1 := get_factor_1(v_rec);
v_factor2 := get_factor_2(v_rec);
v_factor3 := get_factor_3(v_rec);
v_IsMagical := case
when (v_factor1 + v_factor2 + v_factor3) > 10 then
'Y'
else
'N'
end;
v_XML := v_XML || '<MagicalAddressFactor1>' || v_factor1 || '</MagicalAddressFactor1>' ||
'<MagicalAddressFactor2>' || v_factor2 || '</MagicalAddressFactor2>' ||
'<MagicalAddressFactor3>' || v_factor3 || '</MagicalAddressFactor3>' ||
'<IsMagicalAddress>' || v_IsMagical || '</IsMagicalAddress>';
v_XML := v_XML || '</Person>'
END LOOP;
v_XML := v_XML || '</Directory>'
END;
答案 0 :(得分:1)
您的代码有三个问题:
FOR IN variable LOOP
无法正常工作 - 如果您确实需要动态SQL,那么您必须使用表单FOR IN EXECUTE variable
,但更好的是直接编写SQL查询,
但是,如果人数不多,那就不能快速了。
输出XML可能是错误的,因为您缺少转义。
最后两点通过 SQL/XML 函数很好地解决了 - 我只编写了一个简单的例子 - 但它确实非常强大的ANSI / SQL功能(Postgres支持) 。
SELECT xmlelement(NAME "Directory",
xmlagg(xmlelement(NAME "Person",
xmlforest(name AS "Name",
address AS "Address"))))
FROM persons;
答案 1 :(得分:1)
对于OP和未来的读者,可以在需要时将数据库内容迁移到XML文档时考虑使用通用语言。只需通过ODBC / OLEDB驱动程序连接,检索查询并输出到XML文档。使用OP的需求,可以将计算合并到一个选择查询或存储过程中,该过程返回结果集并具有用于文档构建的编码语言导入记录。
下面是包含Java的开源解决方案,其中每个解决方案都使用相应的PostgreSQL驱动程序进行连接(需要安装)。 SQL查询假设get_factor1()
,get_factor2()
,get_factor3()
是内联数据库函数,而Persons在第一列中保留唯一ID。
Java (使用Postgre JDBC driver)
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.OutputKeys;
import java.sql.* ;
import java.util.ArrayList;
import java.io.IOException;
import java.io.File;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
public class SQLtoXML {
public static void main(String[] args) {
String currentDir = new File("").getAbsolutePath();
try {
String url = "jdbc:postgresql://localhost/test";
Properties props = new Properties();
props.setProperty("user","sqluser");
props.setProperty("password","secret");
props.setProperty("ssl","true");
Connection conn = DriverManager.getConnection(url, props);
String url = "jdbc:postgresql://localhost/test?user=sqlduser&password=secret&ssl=true";
Connection conn = DriverManager.getConnection(url);
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT name, address, "
+ "get_factor_1(v_rec) As v_factor1, "
+ "get_factor_2(v_rec) As v_factor2, "
+ "get_factor_3(v_rec) As v_factor3, "
+ " CASE WHEN (get_factor_1(v_rec) + "
+ " get_factor_2(v_rec) + "
+ " get_factor_3(v_rec)) > 10 "
+ " THEN 'Y' ELSE 'N' END As v_isMagical "
+ " FROM Persons;");
// Write to XML document
DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
Document doc = docBuilder.newDocument();
// Root element
Element rootElement = doc.createElement("Directory");
doc.appendChild(rootElement);
// Export table data
ResultSetMetaData rsmd = rs.getMetaData();
int columnsNumber = rsmd.getColumnCount();
while (rs.next()) {
// Data rows
Element personNode = doc.createElement("Person");
rootElement.appendChild(personNode);
Element nameNode = doc.createElement("name");
nameNode.appendChild(doc.createTextNode(rs.getString(2)));
personNode.appendChild(nameNode);
Element addressNode = doc.createElement("address");
addressNode.appendChild(doc.createTextNode(rs.getString(3)));
personNode.appendChild(addressNode);
Element magicaladd1Node = doc.createElement("MagicalAddressFactor1");
magicaladd1Node.appendChild(doc.createTextNode(rs.getString(4)));
personNode.appendChild(magicaladd1Node);
Element magicaladd2Node = doc.createElement("MagicalAddressFactor2");
magicaladd2Node.appendChild(doc.createTextNode(rs.getString(5)));
personNode.appendChild(magicaladd2Node);
Element magicaladd3Node = doc.createElement("MagicalAddressFactor3");
magicaladd3Node.appendChild(doc.createTextNode(rs.getString(6)));
personNode.appendChild(magicaladd3Node);
Element isMagicalNode = doc.createElement("IsMagicalAddress");
isMagicalNode.appendChild(doc.createTextNode(rs.getString(7)));
personNode.appendChild(isMagicalNode);
}
rs.close();
stmt.close();
conn.close();
// Output content to xml file
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
DOMSource source = new DOMSource(doc);
StreamResult result = new StreamResult(new File(currentDir + "\\PostgreXML_java.xml"));
transformer.transform(source, result);
System.out.println("Successfully created xml file!");
} catch (ParserConfigurationException pce) {
System.out.println(pce.getMessage());
} catch (TransformerException tfe) {
System.out.println(tfe.getMessage());
} catch (SQLException err) {
System.out.println(err.getMessage());
}
}
}
Python (使用Psycopg模块)
import psycopg2
import os
import lxml.etree as ET
cd = os.path.dirname(os.path.abspath(__file__))
# DB CONNECTION AND QUERY
db = psycopg2.connect("dbname=test user=postgres")
cur = db.cursor()
cur.execute("SELECT name, address, \
get_factor_1(v_rec) As v_factor1, \
get_factor_2(v_rec) As v_factor2, \
get_factor_3(v_rec) As v_factor3, \
CASE WHEN (get_factor_1(v_rec) + \
get_factor_2(v_rec) + \
get_factor_3(v_rec)) > 10 \
THEN 'Y' ELSE 'N' END As v_isMagical \
FROM Persons;")
# WRITING XML FILE
root = ET.Element('Directory')
for row in cur.fetchall():
personNode = ET.SubElement(root, "Person")
ET.SubElement(personNode, "Name").text = row[1]
ET.SubElement(personNode, "Address").text = row[2]
ET.SubElement(personNode, "MagicalAddressFactor1").text = row[3]
ET.SubElement(personNode, "MagicalAddressFactor2").text = row[4]
ET.SubElement(personNode, "MagicalAddressFactor3").text = row[5]
ET.SubElement(personNode, "IsMagicalAddress").text = row[6]
# CLOSE CURSOR AND DATABASE
cur.close()
db.close()
# OUTPUT XML
tree_out = (ET.tostring(root, pretty_print=True, xml_declaration=True, encoding="UTF-8"))
xmlfile = open(os.path.join(cd, 'PostgreXML_py.xml'),'wb')
xmlfile.write(tree_out)
xmlfile.close()
print("Successfully migrated SQL to XML data!")
PHP (使用Postgre PDO驱动程序)
<?php
$cd = dirname(__FILE__);
// create a dom document with encoding utf8
$domtree = new DOMDocument('1.0', 'UTF-8');
$domtree->formatOutput = true;
$domtree->preserveWhiteSpace = false;
# Opening db connection
$host="root";
$dbuser = "*****";
try {
$dbh = new PDO("pgsql:dbname=$dbname;host=$host", $dbuser, $dbpass);
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$sql = "SELECT name, address,
get_factor_1(v_rec) As v_factor1,
get_factor_2(v_rec) As v_factor2,
get_factor_3(v_rec) As v_factor3,
CASE WHEN (get_factor_1(v_rec) +
get_factor_2(v_rec) +
get_factor_3(v_rec)) > 10
THEN 'Y' ELSE 'N' END As v_isMagical
FROM Persons;";
$STH = $dbh->query($sql);
$STH->setFetchMode(PDO::FETCH_ASSOC);
}
catch(PDOException $e) {
echo $e->getMessage();
exit;
}
/* create the root element of the xml tree */
$xmlRoot = $domtree->createElement("Directory");
$xmlRoot = $domtree->appendChild($xmlRoot);
/* loop query results through child elements */
while($row = $STH->fetch()) {
$personNode = $xmlRoot->appendChild($domtree->createElement('Person'));
$nameNode = $personNode->appendChild($domtree->createElement('Name', $row['name']));
$addNode = $personNode->appendChild($domtree->createElement('Address', $row['address']));
$magadd1Node = $personNode->appendChild($domtree->createElement('MagicalAddressFactor1', $row['v_factor1']));
$magadd2Node = $personNode->appendChild($domtree->createElement('MagicalAddressFactor2', $row['v_factor2']));
$magadd3Node = $personNode->appendChild($domtree->createElement('MagicalAddressFactor3', $row['v_factor3']));
$ismagicalNode = $personNode->appendChild($domtree->createElement('IsMagicalAddress', $row['v_isMagical']));
}
file_put_contents($cd. "/PostgreXML_php.xml", $domtree->saveXML());
echo "\nSuccessfully migrated SQL data into XML!\n";
# Closing db connection
$dbh = null;
exit;
?>
R (使用RPostgreSQL包)
library(RPostgreSQL)
library(XML)
#setwd("C:/path/to/working/folder")
# OPEN DATABASE AND QUERY
drv <- dbDriver("PostgreSQL")
conn <- dbConnect(drv, dbname="tempdb")
df <- sqlQuery(conn, "SELECT name, address,
get_factor_1(v_rec) As v_factor1,
get_factor_2(v_rec) As v_factor2,
get_factor_3(v_rec) As v_factor3,
CASE WHEN (get_factor_1(v_rec) +
get_factor_2(v_rec) +
get_factor_3(v_rec)) > 10
THEN 'Y' ELSE 'N' END As v_isMagical
FROM Persons;")
close(conn)
# CREATE XML FILE
doc = newXMLDoc()
root = newXMLNode("Directory", doc = doc)
# WRITE XML NODES AND DATA
for (i in 1:nrow(df)){
personNode = newXMLNode("Person", parent = root)
nameNode = newXMLNode("name", df$name[i], parent = personNode)
addressNode = newXMLNode("address", df$address[i], parent = personNode)
magicaladdress1Node = newXMLNode("MagicalAddressFactor1", df$v_factor1[i], parent = personNode)
magicaladdress2Node = newXMLNode("MagicalAddressFactor2", df$v_factor2[i], parent = personNode)
magicaladdress3Node = newXMLNode("MagicalAddressFactor3", df$v_factor3[i], parent = personNode)
ismagicalNode = newXMLNode("IsMagicalAddress", df$v_isMagical[i], parent = personNode)
}
# OUTPUT XML CONTENT TO FILE
saveXML(doc, file="PostgreXML_R.xml")
print("Successfully migrated SQL to XML data!")