Can an XML schema be specific by attribute value? - xsd

If I have the following XML:
<variables>
<variable name="age">92</variable>
<variable name="school">Fairview</variable>
<variable name="birthdate">11/13/2012</variable>
</variables>
Is there a way to create a schema where, based on the name attribute value, it then defines the node value (as decimal, string, date)? If so, how?
Update: This is for code in C# so I need to get this schema info using the >NET runtime.
thanks - dave

Here's a schema for your example in Relax NG
datatypes xsd = "http://www.w3.org/2001/XMLSchema-datatypes"
element variable {
((
attribute name {'age'},
xsd:int) |
(
attribute name {'school'},
text) |
(
attribute name {'birthdate'},
xsd:date))
}

Related

How to access xml field with lxml?

Python 3.6, Lxml, Windows 10
I am getting crazy. I want to access the item field. But I always get the error:
AttributeError: 'cython_function_or_method' object has no attribute'item'
Everything else (address fields etc...) I can access without problems. How can I access the item fields (sku, amount etc...)?
I've used this code:
import requests
from lxml import objectify
url = "URL_TO_XML_FILE"
xml_content = requests.get(url).text.encode('utf-8')
xml = objectify.fromstring(xml_content)
for sale in xml.response.sales.sale:
for item in sale.items.item:
print(item.sku)
Here is the beginning of the xml:
<?xml version="1.0" encoding="ISO-8859-1"?>
<getnewsalesresult xmlns="https://pmcdn.priceminister.com/res/schema/getnewsales">
<request>
<version>2017-08-07</version>
<user>SELLER</user>
</request>
<response>
<lastversion>2017-08-07</lastversion>
<sellerid>95029358</sellerid>
<sales>
<sale>
<purchaseid>297453287592813953</purchaseid>
<purchasedate>15/12/2018-19:10</purchasedate>
<deliveryinformation>
<shippingtype>Normal</shippingtype>
<isfullrsl>N</isfullrsl>
<purchasebuyerlogin><![CDATA[LOGIN]]></purchasebuyerlogin>
<purchasebuyeremail>EMAIL</purchasebuyeremail>
<deliveryaddress>
<civility>Mme</civility>
<lastname><![CDATA[Lastname]]></lastname>
<firstname><![CDATA[Firstname]]></firstname>
<address1><![CDATA[STREET]]></address1>
<address2><![CDATA[]]></address2>
<zipcode>13570</zipcode>
<city><![CDATA[Paris]]></city>
<country><![CDATA[France]]></country>
<countryalpha2>FX</countryalpha2>
<phonenumber1></phonenumber1>
<phonenumber2>PHONENUMBER</phonenumber2>
</deliveryaddress>
</deliveryinformation>
<items>
<item>
<sku><![CDATA[SKU1]]></sku>
<advertid>411812243030</advertid>
<advertpricelisted>
<amount>15.99</amount>
<currency>EUR</currency>
</advertpricelisted>
<itemid>551131040</itemid>
<headline><![CDATA[HEADLINE]]></headline>
<itemstatus><![CDATA[REQUESTED]]></itemstatus>
<ispreorder>N</ispreorder>
<isnego>N</isnego>
<negotiationcomment></negotiationcomment>
<price>
<amount>15.99</amount>
<currency>EUR</currency>
</price>
<isrsl>N</isrsl>
<isbn></isbn>
<ean>4363745894373857474; </ean>
<paymentstatus><![CDATA[INCOMING]]></paymentstatus>
<sellerscore></sellerscore>
</item>
</items>
</sale>
<sale>
The problem is that items is actually a method of ObjectifiedElement, so the expression sale.items actually returns the method, because it has precedence.
To get the 'items' object you want, you have to be more explicit about getting the attribute of sale and not looking for methods of the class first, which is the usual python order. This is what python does behind the scene when you access an attribute, and you can do it too:
sale.__getattr__('items')
This will also work (it's a dictionary-like interface to the attributes of an object):
sale.__dict__['items']
The revised code:
import requests
from lxml import objectify
url = "URL_TO_XML_FILE"
xml_content = requests.get(url).text.encode('utf-8')
xml = objectify.fromstring(xml_content)
for sale in xml.response.sales.sale:
for item in sale.__dict__['items'].item:
print(item.sku)
Another way to deal with this is to avoid using the flaky attribute interface:
for sale in xml['response']['sales']['sale']:
for item in sale['items']['item']:
print(item['sku'])
Using the dict-like indexing interface, you never have to worry about certain attributes names (which includes such common words as items, index, keys, remove, replace, tag, set, text, and values) returning surprising results.

How to get the Structure/Template id by Structure/Template name

I have a requirement that, Need to create JournalArticle with Structure and Template.While creating JournalArticle the method expecting the StructureId and TemplateId but these are generated by Liferay.So by name how can i get Id's of both.
Create and execute a DynamicQuery, like so (just replace Template with Structure to get structures):
DynamicQuery q = DynamicQueryFactoryUtil.forClass(DDMTemplate.class)
.add(PropertyFactoryUtil.forName("name").like("%YOUR NAME%"));
List<DDMTemplate> templates = DDMTemplateLocalServiceUtil.dynamicQuery(q);
You have to use like since the names of the structures/templates are saved like so:
<?xml version='1.0' encoding='UTF-8'?>
<root available-locales="de_DE" default-locale="de_DE">
<Name language-id="de_DE">YOUR NAME</Name>
</root>
There can be different names for different locales.
You can get StructureId (called DDMStructure) with this code
long classNameIdJournalArticle = ClassNameLocalServiceUtil.getClassNameId(JournalArticle.class);
DDMStructure ddmStructure = DDMStructureLocalServiceUtil.getStructure(groupId, classNameIdJournalArticle, "myDDMStructureName");
And TemplateId (called DDMTemplate) with this code
DDMTemplate ddmTemplate = DDMTemplateLocalServiceUtil.getTemplate(groupId, classNameIdDDMStructure, "ddmTemplateName");

JAXB -field based on two sibling XML elements

for example i have this xml:
<xml>
<a>1</a>
<b>2</b>
</xml>
and this class:
#XmlRootElement(name = "xml")
public class xml{
int aPlusb;
....
}
i know how to create an XmlAdapter but i would like it to set the filed aPlusb to be the plus between the value of element a and the value of filed b.
is there a way to do this in JAXB without making an XmlTransient field and calculate it separately?

JAXB xjc: How to generate code for Strings that returns empty if the value is null?

Given the following example xsd snippet:
< xs:attribute name="SEGMENT" default="" use="optional" type="xs:string"/ >
when xjc generates the class containing the SEGMENT bean attribute, the following getter is auto-generated:
public String getSEGMENT() {
if (segment == null) {
return "";
} else {
return segment;
}
}
My question is how do you get it do the same for xs:element objects? In other words, given the following xsd snippet:
< xs:element name="NAME" default="" type="xs:string"/ >
I want to know if I can get xjc to generate the following:
public String getNAME() {
if (name == null) {
return "";
} else {
return name;
}
}
How can this be done?
JAXB doesn't generate the same code for an element with default value as it does for an attribute with default value because the XML schema differentiates between element and attribute defaults:
Default values of both attributes and elements are declared using the default attribute, although this attribute has a slightly different consequence in each case. When an attribute is declared with a default value, the value of the attribute is whatever value appears as the attribute's value in an instance document; if the attribute does not appear in the instance document, the schema processor provides the attribute with a value equal to that of the default attribute. Note that default values for attributes only make sense if the attributes themselves are optional, and so it is an error to specify both a default value and anything other than a value of optional for use.
The schema processor treats defaulted elements slightly differently. When an element is declared with a default value, the value of the element is whatever value appears as the element's content in the instance document; if the element appears without any content, the schema processor provides the element with a value equal to that of the default attribute. However, if the element does not appear in the instance document, the schema processor does not provide the element at all. In summary, the differences between element and attribute defaults can be stated as: Default attribute values apply when attributes are missing, and default element values apply when elements are empty.
You can always count on the default value for a missing attribute (from here the special getter) but there is a catch with a missing element value.
Nonetheless, when you unmarshall an instance, the unmarshaller knows how to handle the default value. See here for details:
Element default values and marshalling
Element default values and unmarshalling
XJC won't add the getter code or initialize the fields with the default value, so if you need the "null safe check" you can either add it yourself manually after the code is generated by XJC or try to use some plugin to do it automatically:
JAXB 2 Default Value Plugin
CXF XJC Default Value Plugin

Parse XML using Groovy: Override charset in declaration and add XML processing instruction

My initial question have been answered, but that did just open up for further issues.
Example code
Using Groovy 2.0.5 JVM 1.6.0_31
import groovy.xml.*
import groovy.xml.dom.DOMCategory
def xml = '''<?xml version="1.0" encoding="UTF-16"?>
| <?xml-stylesheet type="text/xsl" href="Bp8DefaultView.xsl"?>
|<root>
| <Settings>
| <Setting name="CASEID_SEQUENCE_SIZE">
| <HandlerURL>
| <![CDATA[ admin/MainWindow.jsp ]]>
| </HandlerURL>
| </Setting>
| <Setting name="SOMETHING_ELSE">
| <HandlerURL>
| <![CDATA[ admin/MainWindow.jsp ]]>
| </HandlerURL>
| </Setting>
| </Settings>
|</root>'''.stripMargin()
def document = DOMBuilder.parse( new StringReader( xml ) )
def root = document.documentElement
// Edit: Added the line below
def pi = document.createProcessingInstruction('xml-stylesheet', 'type="text/xsl" href="Bp8DefaultView.xsl"');
// Edit #2: Added line below
document.insertBefore(pi, root)
use(DOMCategory) {
root.Settings.Setting.each {
if( it.'#name' == 'CASEID_SEQUENCE_SIZE' ) {
it[ '#value' ] = 100
}
}
}
def outputfile = new File( 'c:/temp/output.xml' )
XmlUtil.serialize( root , new PrintWriter(outputfile))
// Edit #2: Changed from root to document.documentElement to see if that
// would make any difference
println XmlUtil.serialize(document.documentElement)
Problem description
I'm trying to parse a XML-file exported from a third party tool, and before promoting it to stage and production I need to replace certain attribute values. That is all ok, but in addition I must keep the encoding and ref. to the stylesheet.
Since this is pretty static it is totally ok to have both the encoding and the stylesheet ref. definition in a property-file, meaning: I do not need first to find the declarations in the original file.
Encoding in declaration issue
As shown in this answer found here on StackOverFlow you can do
new File('c:/data/myutf8.xml').write(f,'utf-8')
I have also tried
XmlUtil.serialize( root , new GroovyPrintStream('c:/temp/output.txt', 'utf-16'))
but it did not solve the problem for me either. So I have not understood how to override the UTF-value.
Processing instruction issue
Simply, how do I add
<?xml-stylesheet type="text/xsl" href="Bp8DefaultView.xsl"?>
to the output?
Update - This can be done like this
def pi = document.createProcessingInstruction('xml-stylesheet', 'type="text/xsl" href="Bp8DefaultView.xsl"');
The processing instruction is being added like this, this guideline showed me, but still I do not get the output.
document.insertBefore(pi, root) // Fails
All issues in this question has been answered in another question I raised, see Groovy and XML: Not able to insert processing instruction
The trick is that I expected
document.documentElement
to contain the processing instruction. But that is wrong, documentElement is:
...This is a convenience attribute that allows direct access to the child node that is the document element of the document...
Where the processing instruction is just another child node. So what I instead had to use was either the LSSerializer or the Transfomer. See Serialize XML processing instruction before root element for details.

Resources